예제 #1
0
void ClassStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
  ClassScopePtr classScope = m_classScope.lock();
  if (!classScope->isUserClass()) return;
  if (ar) ar->pushScope(classScope);

  switch (m_type) {
  case T_CLASS:                              break;
  case T_ABSTRACT: cg_printf("abstract ");   break;
  case T_FINAL:    cg_printf("final ");      break;
  default:
    ASSERT(false);
  }
  cg_printf("class %s", m_name.c_str());

  if (!m_parent.empty()) {
    cg_printf(" extends %s", m_parent.c_str());
  }

  if (m_base) {
    cg_printf(" implements ");
    m_base->outputPHP(cg, ar);
  }

  cg_indentBegin(" {\n");
  m_classScope.lock()->outputPHP(cg, ar);
  if (m_stmt) m_stmt->outputPHP(cg, ar);
  cg_indentEnd("}\n");

  if (ar) ar->popScope();
}
예제 #2
0
void BlockScope::inferTypes(AnalysisResultPtr ar) {
  if (m_stmt) {
    ar->pushScope(shared_from_this());
    m_stmt->inferTypes(ar);
    ar->popScope();
  }
}
예제 #3
0
void MethodStatement::inferTypes(AnalysisResultPtr ar) {
  FunctionScopePtr funcScope = m_funcScope.lock();
  if (ar->getPhase() == AnalysisResult::FirstInference && m_stmt) {
    if (m_stmt->hasRetExp() ||
        funcScope->inPseudoMain() ||
        funcScope->getReturnType()) {
      bool lastIsReturn = false;
      if (m_stmt->getCount()) {
        StatementPtr lastStmt = (*m_stmt)[m_stmt->getCount()-1];
        if (lastStmt->is(Statement::KindOfReturnStatement)) {
          lastIsReturn = true;
        }
      }
      if (!lastIsReturn &&
          !(funcScope->inPseudoMain() && !Option::GenerateCPPMain)) {
        ExpressionPtr constant =
          funcScope->inPseudoMain() ? CONSTANT("true") : CONSTANT("null");
        ReturnStatementPtr returnStmt =
          ReturnStatementPtr(new ReturnStatement(getLocation(),
            Statement::KindOfReturnStatement, constant));
        m_stmt->addElement(returnStmt);
      }
    }
  }
  ar->pushScope(funcScope);
  if (m_params) {
    m_params->inferAndCheck(ar, NEW_TYPE(Any), false);
  }
  if (m_stmt) {
    m_stmt->inferTypes(ar);
  }
  ar->popScope();
}
예제 #4
0
void ClassStatement::inferTypes(AnalysisResultPtr ar) {
  if (m_stmt) {
    ClassScopePtr classScope = m_classScope.lock();
    ar->pushScope(classScope);
    m_stmt->inferTypes(ar);
    ar->popScope();
  }
}
예제 #5
0
StatementPtr InterfaceStatement::postOptimize(AnalysisResultPtr ar) {
  ar->postOptimize(m_base);
  if (m_stmt) {
    ClassScopePtr classScope = m_classScope.lock();
    ar->pushScope(classScope);
    ar->postOptimize(m_stmt);
    ar->popScope();
  }
  return StatementPtr();
}
예제 #6
0
void ClassStatement::onParse(AnalysisResultPtr ar) {
  ClassScope::KindOf kindOf = ClassScope::KindOfObjectClass;
  switch (m_type) {
  case T_CLASS:     kindOf = ClassScope::KindOfObjectClass;   break;
  case T_ABSTRACT:  kindOf = ClassScope::KindOfAbstractClass; break;
  case T_FINAL:     kindOf = ClassScope::KindOfFinalClass;    break;
  default:
    ASSERT(false);
  }

  vector<string> bases;
  if (!m_parent.empty()) {
    bases.push_back(m_parent);
    ar->addNonFinal(m_parent);
  }
  if (m_base) m_base->getStrings(bases);
  StatementPtr stmt = dynamic_pointer_cast<Statement>(shared_from_this());
  ClassScopePtr classScope(new ClassScope(kindOf, m_originalName, m_parent,
                                          bases, m_docComment,
                                          stmt, ar->getFileScope()));
  m_classScope = classScope;
  if (!ar->getFileScope()->addClass(ar, classScope)) {
    m_ignored = true;
    return;
  }
  ar->recordClassSource(m_name, ar->getFileScope()->getName());

  if (m_stmt) {
    ar->pushScope(classScope);
    bool seenConstruct = false;
    for (int i = 0; i < m_stmt->getCount(); i++) {
      MethodStatementPtr meth =
        dynamic_pointer_cast<MethodStatement>((*m_stmt)[i]);
      if (meth && meth->getName() == "__construct") {
        seenConstruct = true;
        break;
      }
    }
    for (int i = 0; i < m_stmt->getCount(); i++) {
      if (!seenConstruct) {
        MethodStatementPtr meth =
          dynamic_pointer_cast<MethodStatement>((*m_stmt)[i]);
        if (meth && classScope && meth->getName() == classScope->getName()
         && !meth->getModifiers()->isStatic()) {
          // class-name constructor
          classScope->setAttribute(ClassScope::classNameConstructor);
        }
      }
      IParseHandlerPtr ph = dynamic_pointer_cast<IParseHandler>((*m_stmt)[i]);
      ph->onParse(ar);
    }
    ar->popScope();
  }
}
예제 #7
0
StatementPtr InterfaceStatement::preOptimize(AnalysisResultPtr ar) {
  ar->preOptimize(m_base);
  if (m_stmt) {
    ClassScopePtr classScope = m_classScope.lock();
    ar->pushScope(classScope);
    ar->preOptimize(m_stmt);
    ar->popScope();
  }
  if (ar->getPhase() >= AnalysisResult::AnalyzeAll) {
    checkVolatile(ar);
  }
  return StatementPtr();
}
예제 #8
0
void InterfaceStatement::inferTypes(AnalysisResultPtr ar) {
  vector<string> bases;
  if (m_base) m_base->getStrings(bases);
  for (unsigned int i = 0; i < bases.size(); i++) {
    addUserClass(ar, bases[i]);
  }

  if (m_stmt) {
    ClassScopePtr classScope = m_classScope.lock();
    ar->pushScope(classScope);
    m_stmt->inferTypes(ar);
    ar->popScope();
  }
}
예제 #9
0
void ClassStatement::analyzeProgramImpl(AnalysisResultPtr ar) {
  vector<string> bases;
  if (!m_parent.empty()) bases.push_back(m_parent);
  if (m_base) m_base->getStrings(bases);
  for (unsigned int i = 0; i < bases.size(); i++) {
    string className = bases[i];
    addUserClass(ar, bases[i]);
  }

  ClassScopePtr classScope = m_classScope.lock();
  if (hasHphpNote("Volatile")) {
    classScope->setVolatile();
  }

  checkVolatile(ar);

  if (m_stmt) {
    ar->pushScope(classScope);
    m_stmt->analyzeProgram(ar);
    ar->popScope();
  }
  if (ar->getPhase() != AnalysisResult::AnalyzeAll) return;
  DependencyGraphPtr dependencies = ar->getDependencyGraph();
  for (unsigned int i = 0; i < bases.size(); i++) {
    ClassScopePtr cls = ar->findClass(bases[i]);
    if (cls) {
      if ((!cls->isInterface() && (m_parent.empty() || i > 0 )) ||
          (cls->isInterface() && (!m_parent.empty() && i == 0 ))) {
        ar->getCodeError()->record(CodeError::InvalidDerivation,
                                   shared_from_this(), ConstructPtr(),
                                   cls->getOriginalName().c_str());
      }
      if (dependencies->checkCircle(DependencyGraph::KindOfClassDerivation,
                                    m_originalName,
                                    cls->getOriginalName())) {
        ar->getCodeError()->record(CodeError::InvalidDerivation,
                                   shared_from_this(), ConstructPtr(),
                                   cls->getOriginalName().c_str());
        m_parent = "";
        m_base = ExpressionListPtr();
        classScope->clearBases();
      } else if (cls->isUserClass()) {
        dependencies->add(DependencyGraph::KindOfClassDerivation,
                          ar->getName(),
                          m_originalName, shared_from_this(),
                          cls->getOriginalName(), cls->getStmt());
      }
    }
  }
}
예제 #10
0
void FunctionStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
  FunctionScopePtr funcScope = m_funcScope.lock();
  if (!funcScope->isUserFunction()) return;
  if (ar) ar->pushScope(funcScope);

  cg_printf("function ");
  if (m_ref) cg_printf("&");
  cg_printf("%s(", m_name.c_str());
  if (m_params) m_params->outputPHP(cg, ar);
  cg_indentBegin(") {\n");

  m_funcScope.lock()->outputPHP(cg, ar);
  if (m_stmt) m_stmt->outputPHP(cg, ar);
  cg_indentEnd("}\n");

  if (ar) ar->popScope();
}
예제 #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
void ClassStatement::analyzeProgram(AnalysisResultPtr ar) {
  vector<string> bases;
  if (!m_parent.empty()) bases.push_back(m_parent);
  if (m_base) m_base->getStrings(bases);
  for (unsigned int i = 0; i < bases.size(); i++) {
    string className = bases[i];
    addUserClass(ar, bases[i]);
  }

  ClassScopePtr classScope = m_classScope.lock();
  if (hasHphpNote("Volatile")) classScope->setVolatile();
  FunctionScopePtr func = ar->getFunctionScope();
  // redeclared classes are automatically volatile
  if (classScope->isVolatile()) {
    func->getVariables()->setAttribute(VariableTable::NeedGlobalPointer);
  }
  if (m_stmt) {
    ar->pushScope(classScope);
    m_stmt->analyzeProgram(ar);
    ar->popScope();
  }
  DependencyGraphPtr dependencies = ar->getDependencyGraph();
  for (unsigned int i = 0; i < bases.size(); i++) {
    ClassScopePtr cls = ar->findClass(bases[i]);
    if (cls) {
      if (dependencies->checkCircle(DependencyGraph::KindOfClassDerivation,
                                    m_originalName,
                                    cls->getOriginalName())) {
        ClassScopePtr classScope = m_classScope.lock();
        ar->getCodeError()->record(CodeError::InvalidDerivation,
                                   shared_from_this(), ConstructPtr(),
                                   cls->getOriginalName());
        m_parent = "";
        m_base = ExpressionListPtr();
        classScope->clearBases();
      } else if (cls->isUserClass()) {
        dependencies->add(DependencyGraph::KindOfClassDerivation,
                          ar->getName(),
                          m_originalName, shared_from_this(),
                          cls->getOriginalName(), cls->getStmt());
      }
    }
  }
}
예제 #13
0
void InterfaceStatement::analyzeProgramImpl(AnalysisResultPtr ar) {
  ClassScopePtr classScope = m_classScope.lock();
  if (hasHphpNote("Volatile")) classScope->setVolatile();
  if (m_stmt) {
    classScope->setIncludeLevel(ar->getIncludeLevel());
    ar->pushScope(classScope);
    m_stmt->analyzeProgram(ar);
    ar->popScope();
  }
  ar->recordClassSource(m_name, ar->getFileScope()->getName());

  checkVolatile(ar);

  if (ar->getPhase() != AnalysisResult::AnalyzeAll) return;
  vector<string> bases;
  if (m_base) m_base->getStrings(bases);
  DependencyGraphPtr dependencies = ar->getDependencyGraph();
  for (unsigned int i = 0; i < bases.size(); i++) {
    ClassScopePtr cls = ar->findClass(bases[i]);
    if (cls) {
      if (!cls->isInterface()) {
        ar->getCodeError()->record(CodeError::InvalidDerivation,
                                   shared_from_this(), ConstructPtr(),
                                   cls->getOriginalName());
      }
      if (dependencies->checkCircle(DependencyGraph::KindOfClassDerivation,
                                    m_originalName,
                                    cls->getOriginalName())) {
        ClassScopePtr classScope = m_classScope.lock();
        ar->getCodeError()->record(CodeError::InvalidDerivation,
                                   shared_from_this(), ConstructPtr(),
                                   cls->getOriginalName());
        m_base = ExpressionListPtr();
        classScope->clearBases();
      } else if (cls->isUserClass()) {
        dependencies->add(DependencyGraph::KindOfClassDerivation,
                          ar->getName(),
                          m_originalName, shared_from_this(),
                          cls->getOriginalName(), cls->getStmt());
      }
    }
  }
}
예제 #14
0
void MethodStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
  FunctionScopePtr funcScope = m_funcScope.lock();
  if (ar) ar->pushScope(funcScope);

  m_modifiers->outputPHP(cg, ar);
  cg.printf(" function ");
  if (m_ref) cg.printf("&");
  cg.printf("%s(", m_originalName.c_str());
  if (m_params) m_params->outputPHP(cg, ar);
  if (m_stmt) {
    cg.indentBegin(") {\n");
    funcScope->outputPHP(cg, ar);
    m_stmt->outputPHP(cg, ar);
    cg.indentEnd("}\n");
  } else {
    cg.printf(");\n");
  }

  if (ar) ar->popScope();
}
예제 #15
0
StatementPtr MethodStatement::preOptimize(AnalysisResultPtr ar) {
  ar->preOptimize(m_modifiers);
  ar->preOptimize(m_params);
  FunctionScopePtr funcScope = m_funcScope.lock();
  ar->pushScope(funcScope);
  if (ar->getPhase() != AnalysisResult::AnalyzeInclude &&
      AliasManager::doLocalCopyProp()) {
    bool flag;
    do {
      AliasManager am;
      MethodStatementPtr self =
        static_pointer_cast<MethodStatement>(shared_from_this());
      flag = am.optimize(ar, self);
      ar->preOptimize(m_stmt);
    } while (flag);
  } else {
    ar->preOptimize(m_stmt);
  }
  ar->popScope();
  return StatementPtr();
}
ExpressionPtr ClassConstantExpression::preOptimize(AnalysisResultPtr ar) {
  if (ar->getPhase() < AnalysisResult::FirstPreOptimize) {
    return ExpressionPtr();
  }
  if (m_redeclared) return ExpressionPtr();
  ClassScopePtr cls = ar->resolveClass(m_className);
  if (!cls || cls->isRedeclaring()) return ExpressionPtr();
  ConstantTablePtr constants = cls->getConstants();
  if (constants->isExplicitlyDeclared(m_varName)) {
    ConstructPtr decl = constants->getValue(m_varName);
    if (decl) {
      ExpressionPtr value = dynamic_pointer_cast<Expression>(decl);
      if (!m_visited) {
        m_visited = true;
        ar->pushScope(cls);
        ExpressionPtr optExp = value->preOptimize(ar);
        ar->popScope();
        m_visited = false;
        if (optExp) value = optExp;
      }
      if (value->isScalar()) {
        // inline the value
        if (value->is(Expression::KindOfScalarExpression)) {
          ScalarExpressionPtr exp =
            dynamic_pointer_cast<ScalarExpression>(Clone(value));
          exp->setComment(getText());
          return exp;
        } else if (value->is(Expression::KindOfConstantExpression)) {
          // inline the value
          ConstantExpressionPtr exp =
            dynamic_pointer_cast<ConstantExpression>(Clone(value));
          exp->setComment(getText());
          return exp;
        }
      }
    }
  }
  return ExpressionPtr();
}
예제 #17
0
void InterfaceStatement::onParse(AnalysisResultPtr ar) {
  vector<string> bases;
  if (m_base) m_base->getStrings(bases);

  StatementPtr stmt = dynamic_pointer_cast<Statement>(shared_from_this());
  ClassScopePtr classScope(new ClassScope(ClassScope::KindOfInterface,
                                          m_name, "", bases, m_docComment, stmt,
                                          ar->getFileScope()));
  m_classScope = classScope;
  ar->getFileScope()->addClass(ar, classScope);
  ar->getDependencyGraph()->addParent(DependencyGraph::KindOfProgramUserClass,
                                      "", m_originalName, stmt);

  if (m_stmt) {
    ar->pushScope(classScope);
    for (int i = 0; i < m_stmt->getCount(); i++) {
      IParseHandlerPtr ph = dynamic_pointer_cast<IParseHandler>((*m_stmt)[i]);
      ph->onParse(ar);
    }
    ar->popScope();
  }
}
예제 #18
0
void MethodStatement::outputCPPStaticMethodWrapper(CodeGenerator &cg,
                                                   AnalysisResultPtr ar,
                                                   const char *cls) {
  if (!m_modifiers->isStatic() || !m_stmt) return;
  FunctionScopePtr funcScope = m_funcScope.lock();
  ar->pushScope(funcScope);
  m_modifiers->outputCPP(cg, ar);
  TypePtr type = funcScope->getReturnType();
  if (type) {
    type->outputCPPDecl(cg, ar);
  } else {
    cg.printf("void");
  }
  cg.printf(" %s%s(", Option::MethodPrefix, m_name.c_str());
  CodeGenerator::Context old = cg.getContext();
  cg.setContext(CodeGenerator::CppStaticMethodWrapper);
  funcScope->outputCPPParamsDecl(cg, ar, m_params, true);
  cg.setContext(old);
  cg.printf(") { %s%s%s(\"%s\"", type ? "return " : "",
            Option::MethodImplPrefix, m_name.c_str(),
            cls);
  if (funcScope->isVariableArgument()) {
    cg.printf(", num_args");
  }
  if (m_params) {
    for (int i = 0; i < m_params->getCount(); i++) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
      ASSERT(param);
      cg.printf(", %s%s", Option::VariablePrefix, param->getName().c_str());
    }
  }
  if (funcScope->isVariableArgument()) {
    cg.printf(", args");
  }
  cg.printf("); }\n");
  ar->popScope();
}
예제 #19
0
void InterfaceStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
  ClassScopePtr classScope = m_classScope.lock();

  if (cg.getOutput() == CodeGenerator::InlinedPHP ||
      cg.getOutput() == CodeGenerator::TrimmedPHP) {
    if (!classScope->isUserClass()) {
      return;
    }
  }

  if (ar) ar->pushScope(classScope);

  cg.printf("interface %s", m_name.c_str());
  if (m_base) {
    cg.printf(" extends ");
    m_base->outputPHP(cg, ar);
  }
  cg.indentBegin(" {\n");
  m_classScope.lock()->outputPHP(cg, ar);
  if (m_stmt) m_stmt->outputPHP(cg, ar);
  cg.indentEnd("}\n");

  if (ar) ar->popScope();
}
예제 #20
0
void ClassStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  ClassScopePtr classScope = m_classScope.lock();
  if (cg.getContext() == CodeGenerator::NoContext) {
    if (classScope->isRedeclaring()) {
      cg_printf("g->%s%s = ClassStaticsPtr(NEW(%s%s)());\n",
                Option::ClassStaticsObjectPrefix,
                cg.formatLabel(m_name).c_str(),
                Option::ClassStaticsPrefix, classScope->getId(cg).c_str());
      cg_printf("g->%s%s = &%s%s;\n",
                Option::ClassStaticsCallbackPrefix,
                cg.formatLabel(m_name).c_str(),
                Option::ClassWrapperFunctionPrefix,
                classScope->getId(cg).c_str());
    }
    if (classScope->isVolatile()) {
      cg_printf("g->CDEC(%s) = true;\n", m_name.c_str());
    }
    const vector<string> &bases = classScope->getBases();
    for (vector<string>::const_iterator it = bases.begin();
         it != bases.end(); ++it) {
      ClassScopePtr base = ar->findClass(*it);
      if (base && base->isVolatile()) {
        cg_printf("checkClassExists(\"%s\", g);\n",
                  base->getOriginalName().c_str());
      }
    }
    return;
  }

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

  ar->pushScope(classScope);
  string clsNameStr = classScope->getId(cg);
  const char *clsName = clsNameStr.c_str();
  bool redeclared = classScope->isRedeclaring();
  switch (cg.getContext()) {
  case CodeGenerator::CppForwardDeclaration:
    if (Option::GenerateCPPMacros) {
      cg_printf("FORWARD_DECLARE_CLASS(%s)\n", clsName);
      if (redeclared) {
        cg_printf("FORWARD_DECLARE_REDECLARED_CLASS(%s)\n", clsName);
      }
    }
    if (m_stmt) {
      cg.setContext(CodeGenerator::CppClassConstantsDecl);
      m_stmt->outputCPP(cg, ar);
      cg.setContext(CodeGenerator::CppForwardDeclaration);
    }
    break;
  case CodeGenerator::CppDeclaration:
    {
      bool system = cg.getOutput() == CodeGenerator::SystemCPP;
      ClassScopePtr parCls;
      if (!m_parent.empty()) {
        parCls = ar->findClass(m_parent);
        if (parCls && parCls->isRedeclaring()) parCls.reset();
      }
      cg_printf("class %s%s", Option::ClassPrefix, clsName);
      if (!m_parent.empty() && classScope->derivesDirectlyFrom(ar, m_parent)) {
        if (!parCls) {
          cg_printf(" : public DynamicObjectData");
        } else {
          cg_printf(" : public %s%s", Option::ClassPrefix,
                    parCls->getId(cg).c_str());
        }
      } else {
        if (classScope->derivesFromRedeclaring()) {
          cg_printf(" : public DynamicObjectData");
        } else if (system) {
          cg_printf(" : public ExtObjectData");
        } else {
          cg_printf(" : public ObjectData");
        }
      }
      if (m_base && Option::UseVirtualDispatch) {
        for (int i = 0; i < m_base->getCount(); i++) {
          ScalarExpressionPtr exp =
            dynamic_pointer_cast<ScalarExpression>((*m_base)[i]);
          const char *intf = exp->getString().c_str();
          ClassScopePtr intfClassScope = ar->findClass(intf);
          if (intfClassScope && !intfClassScope->isRedeclaring() &&
              classScope->derivesDirectlyFrom(ar, intf) &&
              (!parCls || !parCls->derivesFrom(ar, intf, true, false))) {
            string id = intfClassScope->getId(cg);
            cg_printf(", public %s%s", Option::ClassPrefix, id.c_str());
          }
        }
      }
      cg_indentBegin(" {\n");

      if (Option::GenerateCPPMacros) {
        // Get all of this class's ancestors
        vector<string> bases;
        getAllParents(ar, bases);
        // Eliminate duplicates
        sort(bases.begin(), bases.end());
        bases.erase(unique(bases.begin(), bases.end()), bases.end());

        cg_indentBegin("BEGIN_CLASS_MAP(%s)\n",
                       Util::toLower(classScope->getName()).c_str());
        for (unsigned int i = 0; i < bases.size(); i++) {
          cg_printf("PARENT_CLASS(%s)\n", bases[i].c_str());
        }
        if (classScope->derivesFromRedeclaring()) {
          cg_printf("CLASS_MAP_REDECLARED()\n");
        }
        cg_indentEnd("END_CLASS_MAP(%s)\n", clsName);
      }

      if (Option::GenerateCPPMacros) {
        bool dyn = (!parCls && !m_parent.empty()) ||
          classScope->derivesFromRedeclaring() ==
          ClassScope::DirectFromRedeclared;
        bool idyn = parCls && classScope->derivesFromRedeclaring() ==
          ClassScope::IndirectFromRedeclared;
        bool redec = classScope->isRedeclaring();
        if (!classScope->derivesFromRedeclaring()) {
          outputCPPClassDecl(cg, ar, clsName, m_originalName.c_str(),
                             parCls ? parCls->getId(cg).c_str() : "ObjectData");
        } else {
          cg_printf("DECLARE_DYNAMIC_CLASS(%s, %s, %s)\n", clsName,
                    m_originalName.c_str(),
                    dyn || !parCls ? "DynamicObjectData" :
                    parCls->getId(cg).c_str());
        }
        if (system || Option::EnableEval >= Option::LimitedEval) {
          cg_printf("DECLARE_INVOKES_FROM_EVAL\n");
        }
        if (dyn || idyn || redec) {
          if (redec) {
            cg_printf("DECLARE_ROOT;\n");
             if (!dyn && !idyn) {
               cg_printf("private: ObjectData* root;\n");
               cg_printf("public:\n");
               cg_printf("virtual ObjectData *getRoot() { return root; }\n");
             }
          }

          string conInit = ":";
          if (dyn) {
            conInit += "DynamicObjectData(\"" + m_parent + "\", r)";
          } else if (idyn) {
            conInit += string(Option::ClassPrefix) + parCls->getId(cg) +
              "(r?r:this)";
          } else {
            conInit += "root(r?r:this)";
          }

          cg_printf("%s%s(ObjectData* r = NULL)%s {}\n",
                    Option::ClassPrefix, clsName,
                    conInit.c_str());
        }
      }

      cg_printf("void init();\n",
                Option::ClassPrefix, clsName);

      if (classScope->needLazyStaticInitializer()) {
        cg_printf("static GlobalVariables *lazy_initializer"
                  "(GlobalVariables *g);\n");
      }

      classScope->getVariables()->outputCPPPropertyDecl(cg, ar,
          classScope->derivesFromRedeclaring());

      if (!classScope->getAttribute(ClassScope::HasConstructor)) {
        FunctionScopePtr func = classScope->findFunction(ar, "__construct",
                                                         false);
        if (func && !func->isAbstract() && !classScope->isInterface()) {
          ar->pushScope(func);
          func->outputCPPCreateDecl(cg, ar);
          ar->popScope();
        }
      }
      if (classScope->getAttribute(ClassScope::HasDestructor)) {
        cg_printf("public: virtual void destruct();\n");
      }

      // doCall
      if (classScope->getAttribute(ClassScope::HasUnknownMethodHandler)) {
        cg_printf("Variant doCall(Variant v_name, Variant v_arguments, "
                  "bool fatal);\n");
      }
      // doGet
      if (classScope->getAttribute(ClassScope::HasUnknownPropHandler)) {
        cg_printf("Variant doGet(Variant v_name, bool error);\n");
      }


      if (classScope->isRedeclaring() &&
          !classScope->derivesFromRedeclaring()) {
        cg_printf("Variant doRootCall(Variant v_name, Variant v_arguments, "
                  "bool fatal);\n");
      }

      if (m_stmt) m_stmt->outputCPP(cg, ar);
      {
        set<string> done;
        classScope->outputCPPStaticMethodWrappers(cg, ar, done, clsName);
      }

      if (cg.getOutput() == CodeGenerator::SystemCPP &&
          ar->isBaseSysRsrcClass(clsName) &&
          !classScope->hasProperty("rsrc")) {
        cg_printf("public: Variant %srsrc;\n", Option::PropertyPrefix);
      }

      cg_indentEnd("};\n");

      if (redeclared) {
        cg_indentBegin("class %s%s : public ClassStatics {\n",
                       Option::ClassStaticsPrefix, clsName);
        cg_printf("public:\n");
        cg_printf("DECLARE_OBJECT_ALLOCATION(%s%s);\n",
                  Option::ClassStaticsPrefix, clsName);
        cg_printf("%s%s() : ClassStatics(%d) {}\n",
                  Option::ClassStaticsPrefix, clsName,
                  classScope->getRedeclaringId());
        cg_indentBegin("Variant %sgetInit(const char *s, int64 hash = -1) {\n",
                       Option::ObjectStaticPrefix);
        cg_printf("return %s%s::%sgetInit(s, hash);\n", Option::ClassPrefix,
                  clsName, Option::ObjectStaticPrefix);
        cg_indentEnd("}\n");
        cg_indentBegin("Variant %sget(const char *s, int64 hash = -1) {\n",
                       Option::ObjectStaticPrefix);
        cg_printf("return %s%s::%sget(s, hash);\n", Option::ClassPrefix,
                  clsName, Option::ObjectStaticPrefix);
        cg_indentEnd("}\n");
        cg_indentBegin("Variant &%slval(const char* s, int64 hash = -1) {\n",
                  Option::ObjectStaticPrefix);
        cg_printf("return %s%s::%slval(s, hash);\n", Option::ClassPrefix,
                  clsName, Option::ObjectStaticPrefix);
        cg_indentEnd("}\n");
        cg_indentBegin("Variant %sinvoke(const char *c, const char *s, "
                       "CArrRef params, int64 hash = -1, bool fatal = true) "
                       "{\n",
                  Option::ObjectStaticPrefix);
        cg_printf("return %s%s::%sinvoke(c, s, params, hash, fatal);\n",
                  Option::ClassPrefix, clsName,
                  Option::ObjectStaticPrefix);
        cg_indentEnd("}\n");
        cg_indentBegin("Object create(CArrRef params, bool init = true, "
                       "ObjectData* root = NULL) {\n");
        cg_printf("return Object((NEW(%s%s)(root))->"
                  "dynCreate(params, init));\n",
                  Option::ClassPrefix, clsName);
        cg_indentEnd("}\n");
        cg_indentBegin("Variant %sconstant(const char* s) {\n",
                       Option::ObjectStaticPrefix);
        cg_printf("return %s%s::%sconstant(s);\n", Option::ClassPrefix,
                  clsName, Option::ObjectStaticPrefix);
        cg_indentEnd("}\n");
        cg_indentBegin("Variant %sinvoke_from_eval(const char *c, "
                       "const char *s, Eval::VariableEnvironment &env, "
                       "const Eval::FunctionCallExpression *call, "
                       "int64 hash = -1, bool fatal = true) "
                       "{\n",
                       Option::ObjectStaticPrefix);
        cg_printf("return %s%s::%sinvoke_from_eval(c, s, env, call, hash, "
                  "fatal);\n",
                  Option::ClassPrefix, clsName,
                  Option::ObjectStaticPrefix);
        cg_indentEnd("}\n");
        cg_indentEnd("};\n");
      }

      classScope->outputCPPGlobalTableWrappersDecl(cg, ar);
    }
    break;
  case CodeGenerator::CppImplementation:
    if (m_stmt) {
      cg.setContext(CodeGenerator::CppClassConstantsImpl);
      m_stmt->outputCPP(cg, ar);
      cg.setContext(CodeGenerator::CppImplementation);
    }

    classScope->outputCPPSupportMethodsImpl(cg, ar);

    if (redeclared) {
      cg_printf("IMPLEMENT_OBJECT_ALLOCATION(%s%s);\n",
                Option::ClassStaticsPrefix, clsName);
    }

    cg_indentBegin("void %s%s::init() {\n",
                   Option::ClassPrefix, clsName);
    if (!m_parent.empty()) {
      if (classScope->derivesFromRedeclaring() ==
          ClassScope::DirectFromRedeclared) {
        cg_printf("parent->init();\n");
      } else {
        cg_printf("%s%s::init();\n", Option::ClassPrefix, m_parent.c_str());
      }
    }
    if (classScope->getVariables()->
        getAttribute(VariableTable::NeedGlobalPointer)) {
      cg.printDeclareGlobals();
    }
    cg.setContext(CodeGenerator::CppConstructor);
    if (m_stmt) m_stmt->outputCPP(cg, ar);

    // This is lame. Exception base class needs to prepare stacktrace outside
    // of its PHP constructor. Every subclass of exception also needs this
    // stacktrace, so we're adding an artificial __init__ in exception.php
    // and calling it here.
    if (m_name == "exception") {
      cg_printf("{CountableHelper h(this); t___init__();}\n");
    }

    cg_indentEnd("}\n");

    if (classScope->needStaticInitializer()) {
      cg_indentBegin("void %s%s::os_static_initializer() {\n",
                     Option::ClassPrefix, clsName);
      cg.printDeclareGlobals();
      cg.setContext(CodeGenerator::CppStaticInitializer);
      if (m_stmt) m_stmt->outputCPP(cg, ar);
      cg_indentEnd("}\n");
      cg_indentBegin("void %s%s() {\n",
                     Option::ClassStaticInitializerPrefix, clsName);
      cg_printf("%s%s::os_static_initializer();\n",  Option::ClassPrefix,
                clsName);
      cg_indentEnd("}\n");
    }
    if (classScope->needLazyStaticInitializer()) {
      cg_indentBegin("GlobalVariables *%s%s::lazy_initializer("
                     "GlobalVariables *g) {\n", Option::ClassPrefix, clsName);
      cg_indentBegin("if (!g->%s%s) {\n",
                     Option::ClassStaticInitializerFlagPrefix, clsName);
      cg_printf("g->%s%s = true;\n", Option::ClassStaticInitializerFlagPrefix,
                clsName);
      cg.setContext(CodeGenerator::CppLazyStaticInitializer);
      if (m_stmt) m_stmt->outputCPP(cg, ar);
      cg_indentEnd("}\n");
      cg_printf("return g;\n");
      cg_indentEnd("}\n");
    }
    cg.setContext(CodeGenerator::CppImplementation);
    if (m_stmt) m_stmt->outputCPP(cg, ar);

    break;
  case CodeGenerator::CppFFIDecl:
  case CodeGenerator::CppFFIImpl:
    if (m_stmt) m_stmt->outputCPP(cg, ar);
    break;
  case CodeGenerator::JavaFFI:
    {
      if (classScope->isRedeclaring()) break;

      // TODO support PHP namespaces, once HPHP supports it
      string packageName = Option::JavaFFIRootPackage;
      string packageDir = packageName;
      Util::replaceAll(packageDir, ".", "/");

      string outputDir = ar->getOutputPath() + "/" + Option::FFIFilePrefix +
        packageDir + "/";
      Util::mkdir(outputDir);

      // uses a different cg to generate a separate file for each PHP class
      // also, uses the original capitalized class name
      string clsFile = outputDir + getOriginalName() + ".java";
      ofstream fcls(clsFile.c_str());
      CodeGenerator cgCls(&fcls, CodeGenerator::FileCPP);
      cgCls.setContext(CodeGenerator::JavaFFI);

      cgCls.printf("package %s;\n\n", packageName.c_str());
      cgCls.printf("import hphp.*;\n\n");

      printSource(cgCls);

      string clsModifier;
      switch (m_type) {
      case T_CLASS:
        break;
      case T_ABSTRACT:
        clsModifier = "abstract ";
        break;
      case T_FINAL:
        clsModifier = "final ";
        break;
      }
      cgCls.printf("public %sclass %s ", clsModifier.c_str(),
                   getOriginalName().c_str());

      ClassScopePtr parCls;
      if (!m_parent.empty()) parCls = ar->findClass(m_parent);
      if (!m_parent.empty() && classScope->derivesDirectlyFrom(ar, m_parent)
          && parCls && parCls->isUserClass() && !parCls->isRedeclaring()) {
        // system classes are not supported in static FFI translation
        // they shouldn't appear as superclasses as well
        cgCls.printf("extends %s", parCls->getOriginalName().c_str());
      }
      else {
        cgCls.printf("extends HphpObject");
      }
      if (m_base) {
        bool first = true;
        for (int i = 0; i < m_base->getCount(); i++) {
          ScalarExpressionPtr exp =
            dynamic_pointer_cast<ScalarExpression>((*m_base)[i]);
          const char *intf = exp->getString().c_str();
          ClassScopePtr intfClassScope = ar->findClass(intf);
          if (intfClassScope && classScope->derivesFrom(ar, intf, false, false)
           && intfClassScope->isUserClass()) {
            if (first) {
              cgCls.printf(" implements ");
              first = false;
            }
            else {
              cgCls.printf(", ");
            }
            cgCls.printf(intfClassScope->getOriginalName().c_str());
          }
        }
      }

      cgCls.indentBegin(" {\n");

      // constructor for initializing the variant pointer
      cgCls.printf("protected %s(long ptr) { super(ptr); }\n\n",
                   getOriginalName().c_str());

      FunctionScopePtr cons = classScope->findConstructor(ar, true);
      if (cons && !cons->isAbstract() || m_type != T_ABSTRACT) {
        // if not an abstract class and not having an explicit constructor,
        // adds a default constructor
        outputJavaFFIConstructor(cgCls, ar, cons);
      }

      if (m_stmt) m_stmt->outputCPP(cgCls, ar);
      cgCls.indentEnd("}\n");

      fcls.close();
    }
    break;
  case CodeGenerator::JavaFFICppDecl:
  case CodeGenerator::JavaFFICppImpl:
    {
      if (classScope->isRedeclaring()) break;

      if (m_stmt) m_stmt->outputCPP(cg, ar);
      FunctionScopePtr cons = classScope->findConstructor(ar, true);
      if (cons && !cons->isAbstract() || m_type != T_ABSTRACT) {
        outputJavaFFICPPCreator(cg, ar, cons);
      }
    }
    break;
  default:
    ASSERT(false);
    break;
  }

  ar->popScope();
}
예제 #21
0
void ClassStatement::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) {
  ClassScopePtr classScope = m_classScope.lock();
  if (cg.getContext() == CodeGenerator::NoContext) {
    if (classScope->isRedeclaring()) {
      cg.printf("g->%s%s = ClassStaticsPtr(NEW(%s%s)());\n",
                Option::ClassStaticsObjectPrefix, m_name.c_str(),
                Option::ClassStaticsPrefix, classScope->getId().c_str());
    }
    if (classScope->isVolatile()) {
      cg.printf("g->declareClass(\"%s\");\n",
                m_name.c_str());
    }
    return;
  }

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

  ar->pushScope(classScope);
  string clsNameStr = classScope->getId();
  const char *clsName = clsNameStr.c_str();
  bool redeclared = classScope->isRedeclaring();
  switch (cg.getContext()) {
  case CodeGenerator::CppForwardDeclaration:
    if (Option::GenerateCPPMacros) {
      cg.printf("FORWARD_DECLARE_CLASS(%s)\n", clsName);
      if (redeclared) {
        cg.printf("FORWARD_DECLARE_REDECLARED_CLASS(%s)\n", clsName);
      }
    }
    if (m_stmt) {
      cg.setContext(CodeGenerator::CppClassConstantsDecl);
      m_stmt->outputCPP(cg, ar);
      cg.setContext(CodeGenerator::CppForwardDeclaration);
    }
    break;
  case CodeGenerator::CppDeclaration:
    {
      ClassScopePtr parCls;
      if (!m_parent.empty()) parCls = ar->findClass(m_parent);
      cg.printf("class %s%s", Option::ClassPrefix, clsName);
      bool derived = false;
      if (!m_parent.empty() && classScope->derivesFrom(ar, m_parent)) {
        if (parCls->isRedeclaring()) {
          cg.printf(" : public DynamicObjectData");
        } else {
          cg.printf(" : virtual public %s%s", Option::ClassPrefix,
                    parCls->getId().c_str());
        }
        derived = true;
      }
      if (m_base) {
        for (int i = 0; i < m_base->getCount(); i++) {
          ScalarExpressionPtr exp =
            dynamic_pointer_cast<ScalarExpression>((*m_base)[i]);
          const char *intf = exp->getString().c_str();
          ClassScopePtr intfClassScope = ar->findClass(intf);
          if (intfClassScope && classScope->derivesFrom(ar, intf)) {
            // temporary fix for inheriting from a re-declaring class
            string id = intfClassScope->getId();
            if (!derived) {
              derived = true;
              cg.printf(" :");
            } else {
              cg.printf(",");
            }
            cg.printf(" virtual public %s%s", Option::ClassPrefix, id.c_str());
          }
        }
      }
      if (!derived) {
        const char *op = derived ? "," : " :";
        if (classScope->derivesFromRedeclaring()) {
          cg.printf("%s public DynamicObjectData", op);
        } else {
          cg.printf("%s virtual public ObjectData", op);
        }
      }
      cg.indentBegin(" {\n");

      if (Option::GenerateCPPMacros) {
        vector<string> bases;
        getAllParents(ar, bases);

        cg.indentBegin("BEGIN_CLASS_MAP(%s)\n", clsName);
        for (unsigned int i = 0; i < bases.size(); i++) {
          cg.printf("PARENT_CLASS(%s)\n", bases[i].c_str());
        }
        cg.indentEnd("END_CLASS_MAP(%s)\n", clsName);
      }

      if (Option::GenerateCPPMacros) {
        bool dyn = classScope->derivesFromRedeclaring() ==
          ClassScope::DirectFromRedeclared;
        bool idyn = classScope->derivesFromRedeclaring() ==
          ClassScope::IndirectFromRedeclared;
        bool redec = classScope->isRedeclaring();
        if (!classScope->derivesFromRedeclaring()) {
          cg.printf("DECLARE_CLASS(%s, %s, %s)\n", clsName,
                    m_originalName.c_str(),
                    m_parent.empty() ? "ObjectData" : m_parent.c_str());
        } else {
          cg.printf("DECLARE_DYNAMIC_CLASS(%s, %s)\n", clsName,
                    m_originalName.c_str());
        }
        if (cg.getOutput() == CodeGenerator::SystemCPP ||
            Option::EnableEval >= Option::LimitedEval) {
          cg.printf("DECLARE_INVOKES_FROM_EVAL\n");
        }
        if (dyn || idyn || redec) {
          if (redec) {

            cg.indentBegin("Variant %sroot_invoke(const char* s, CArrRef ps, "
                           "int64 h, bool f = true) {\n",
                           Option::ObjectPrefix);
            cg.printf("return root->%sinvoke(s, ps, h, f);\n",
                      Option::ObjectPrefix);
            cg.indentEnd("}\n");
            cg.indentBegin("Variant %sroot_invoke_few_args(const char* s, "
                           "int64 h, int count", Option::ObjectPrefix);
            for (int i = 0; i < Option::InvokeFewArgsCount; i++) {
              cg.printf(", CVarRef a%d = null_variant", i);
            }
            cg.printf(") {\n");
            cg.printf("return root->%sinvoke_few_args(s, h, count",
                      Option::ObjectPrefix);
            for (int i = 0; i < Option::InvokeFewArgsCount; i++) {
              cg.printf(", a%d", i);
            }
            cg.printf(");\n");
            cg.indentEnd("}\n");
            if (!dyn && !idyn) cg.printf("private: ObjectData* root;\n");
            cg.printf("public:\n");
          }

          string conInit = ":";
          if (dyn) {
            conInit += "DynamicObjectData(\"" + m_parent + "\", r)";
          } else if (idyn) {
            conInit += string(Option::ClassPrefix) + parCls->getId() +
              "(r?r:this)";
          } else {
            conInit += "root(r?r:this)";
          }

          cg.printf("%s%s(ObjectData* r = NULL)%s {}\n",
                    Option::ClassPrefix, clsName,
                    conInit.c_str());
        }
      }

      cg.printf("void init();\n",
                Option::ClassPrefix, clsName);

      if (classScope->needLazyStaticInitializer()) {
        cg.printf("static GlobalVariables *lazy_initializer"
                  "(GlobalVariables *g);\n");
      }

      if (!classScope->derivesFromRedeclaring()){
        classScope->getVariables()->outputCPPPropertyDecl(cg, ar);
      }

      if (!classScope->getAttribute(ClassScope::HasConstructor)) {
        FunctionScopePtr func = classScope->findFunction(ar, "__construct",
                                                         false);
        if (func && !func->isAbstract() && !classScope->isInterface()) {
          ar->pushScope(func);
          func->outputCPPCreateDecl(cg, ar);
          ar->popScope();
        }
      }
      if (classScope->getAttribute(ClassScope::HasDestructor)) {
        cg.printf("public: virtual void destruct();\n");
      }

      // doCall
      if (classScope->getAttribute(ClassScope::HasUnknownMethodHandler)) {
        cg.printf("Variant doCall(Variant v_name, Variant v_arguments, "
                  "bool fatal);\n");
      }

      if (m_stmt) m_stmt->outputCPP(cg, ar);
      {
        set<string> done;
        classScope->outputCPPStaticMethodWrappers(cg, ar, done, clsName);
      }

      if (cg.getOutput() == CodeGenerator::SystemCPP &&
          ar->isBaseSysRsrcClass(clsName) &&
          !classScope->hasProperty("rsrc")) {
        cg.printf("public: Variant %srsrc;\n", Option::PropertyPrefix);
      }

      cg.indentEnd("};\n");

      if (redeclared) {
        cg.indentBegin("class %s%s : public ClassStatics {\n",
                       Option::ClassStaticsPrefix, clsName);
        cg.printf("public:\n");
        cg.printf("DECLARE_OBJECT_ALLOCATION(%s%s);\n",
                  Option::ClassStaticsPrefix, clsName);
        cg.printf("%s%s() : ClassStatics(%d) {}\n",
                  Option::ClassStaticsPrefix, clsName,
                  classScope->getRedeclaringId());
        cg.indentBegin("Variant %sget(const char *s, int64 hash = -1) {\n",
                       Option::ObjectStaticPrefix);
        cg.printf("return %s%s::%sget(s, hash);\n", Option::ClassPrefix,
                  clsName, Option::ObjectStaticPrefix);
        cg.indentEnd("}\n");
        cg.indentBegin("Variant &%slval(const char* s, int64 hash = -1) {\n",
                  Option::ObjectStaticPrefix);
        cg.printf("return %s%s::%slval(s, hash);\n", Option::ClassPrefix,
                  clsName, Option::ObjectStaticPrefix);
        cg.indentEnd("}\n");
        cg.indentBegin("Variant %sinvoke(const char *c, const char *s, "
                       "CArrRef params, int64 hash = -1, bool fatal = true) "
                       "{\n",
                  Option::ObjectStaticPrefix);
        cg.printf("return %s%s::%sinvoke(c, s, params, hash, fatal);\n",
                  Option::ClassPrefix, clsName,
                  Option::ObjectStaticPrefix);
        cg.indentEnd("}\n");
        cg.indentBegin("Object create(CArrRef params, bool init = true, "
                       "ObjectData* root = NULL) {\n");
        cg.printf("return Object(%s%s(NEW(%s%s)(root))->"
                  "dynCreate(params, init));\n",
                  Option::SmartPtrPrefix, clsName,
                  Option::ClassPrefix, clsName);
        cg.indentEnd("}\n");
        cg.indentBegin("Variant %sconstant(const char* s) {\n",
                       Option::ObjectStaticPrefix);
        cg.printf("return %s%s::%sconstant(s);\n", Option::ClassPrefix, clsName,
                  Option::ObjectStaticPrefix);
        cg.indentEnd("}\n");
        cg.indentBegin("Variant %sinvoke_from_eval(const char *c, "
                       "const char *s, Eval::VariableEnvironment &env, "
                       "const Eval::FunctionCallExpression *call, "
                       "int64 hash = -1, bool fatal = true) "
                       "{\n",
                       Option::ObjectStaticPrefix);
        cg.printf("return %s%s::%sinvoke_from_eval(c, s, env, call, hash, "
                  "fatal);\n",
                  Option::ClassPrefix, clsName,
                  Option::ObjectStaticPrefix);
        cg.indentEnd("}\n");
        cg.indentEnd("};\n");
      }
    }
    break;
  case CodeGenerator::CppImplementation:
    if (m_stmt) {
      cg.setContext(CodeGenerator::CppClassConstantsImpl);
      m_stmt->outputCPP(cg, ar);
      cg.setContext(CodeGenerator::CppImplementation);
    }

    classScope->outputCPPSupportMethodsImpl(cg, ar);

    if (redeclared) {
      cg.printf("IMPLEMENT_OBJECT_ALLOCATION(%s%s);\n",
                Option::ClassStaticsPrefix, clsName);
    }

    cg.indentBegin("void %s%s::init() {\n",
                   Option::ClassPrefix, clsName);
    if (!m_parent.empty()) {
      if (classScope->derivesFromRedeclaring() ==
          ClassScope::DirectFromRedeclared) {
        cg.printf("parent->init();\n");
      } else {
        cg.printf("%s%s::init();\n", Option::ClassPrefix, m_parent.c_str());
      }
    }
    cg.setContext(CodeGenerator::CppConstructor);
    if (m_stmt) m_stmt->outputCPP(cg, ar);
    cg.indentEnd("}\n");

    if (classScope->needStaticInitializer()) {
      cg.indentBegin("void %s%s::os_static_initializer() {\n",
                     Option::ClassPrefix, clsName);
      cg.printDeclareGlobals();
      cg.setContext(CodeGenerator::CppStaticInitializer);
      if (m_stmt) m_stmt->outputCPP(cg, ar);
      cg.indentEnd("}\n");
      cg.indentBegin("void %s%s() {\n",
                     Option::ClassStaticInitializerPrefix, clsName);
      cg.printf("%s%s::os_static_initializer();\n",  Option::ClassPrefix,
                clsName);
      cg.indentEnd("}\n");
    }
    if (classScope->needLazyStaticInitializer()) {
      cg.indentBegin("GlobalVariables *%s%s::lazy_initializer("
                     "GlobalVariables *g) {\n", Option::ClassPrefix, clsName);
      cg.indentBegin("if (!g->%s%s) {\n",
                     Option::ClassStaticInitializerFlagPrefix, clsName);
      cg.printf("g->%s%s = true;\n", Option::ClassStaticInitializerFlagPrefix,
                clsName);
      cg.setContext(CodeGenerator::CppLazyStaticInitializer);
      if (m_stmt) m_stmt->outputCPP(cg, ar);
      cg.indentEnd("}\n");
      cg.printf("return g;\n");
      cg.indentEnd("}\n");
    }
    cg.setContext(CodeGenerator::CppImplementation);
    if (m_stmt) m_stmt->outputCPP(cg, ar);

    break;
  case CodeGenerator::CppFFIDecl:
  case CodeGenerator::CppFFIImpl:
    if (m_stmt) m_stmt->outputCPP(cg, ar);
    break;
  case CodeGenerator::JavaFFI:
    {
      if (classScope->isRedeclaring()) break;

      // TODO support PHP namespaces, once HPHP supports it
      string packageName = Option::JavaFFIRootPackage;
      string packageDir = packageName;
      Util::replaceAll(packageDir, ".", "/");

      string outputDir = ar->getOutputPath() + "/" + Option::FFIFilePrefix +
        packageDir + "/";
      Util::mkdir(outputDir);

      // uses a different cg to generate a separate file for each PHP class
      // also, uses the original capitalized class name
      string clsFile = outputDir + getOriginalName() + ".java";
      ofstream fcls(clsFile.c_str());
      CodeGenerator cgCls(&fcls, CodeGenerator::FileCPP);
      cgCls.setContext(CodeGenerator::JavaFFI);

      cgCls.printf("package %s;\n\n", packageName.c_str());
      cgCls.printf("import hphp.*;\n\n");

      printSource(cgCls);

      string clsModifier;
      switch (m_type) {
      case T_CLASS:
        break;
      case T_ABSTRACT:
        clsModifier = "abstract ";
        break;
      case T_FINAL:
        clsModifier = "final ";
        break;
      }
      cgCls.printf("public %sclass %s ", clsModifier.c_str(),
                   getOriginalName().c_str());

      ClassScopePtr parCls;
      if (!m_parent.empty()) parCls = ar->findClass(m_parent);
      if (!m_parent.empty() && classScope->derivesFrom(ar, m_parent)
       && parCls->isUserClass() && !parCls->isRedeclaring()) {
        // system classes are not supported in static FFI translation
        // they shouldn't appear as superclasses as well
        cgCls.printf("extends %s", parCls->getOriginalName());
      }
      else {
        cgCls.printf("extends HphpObject");
      }
      if (m_base) {
        bool first = true;
        for (int i = 0; i < m_base->getCount(); i++) {
          ScalarExpressionPtr exp =
            dynamic_pointer_cast<ScalarExpression>((*m_base)[i]);
          const char *intf = exp->getString().c_str();
          ClassScopePtr intfClassScope = ar->findClass(intf);
          if (intfClassScope && classScope->derivesFrom(ar, intf)
           && intfClassScope->isUserClass()) {
            if (first) {
              cgCls.printf(" implements ");
              first = false;
            }
            else {
              cgCls.printf(", ");
            }
            cgCls.printf(intfClassScope->getOriginalName());
          }
        }
      }

      cgCls.indentBegin(" {\n");

      // constructor for initializing the variant pointer
      cgCls.printf("protected %s(long ptr) { super(ptr); }\n\n",
                   getOriginalName().c_str());

      FunctionScopePtr cons = classScope->findConstructor(ar, true);
      if (cons && !cons->isAbstract() || m_type != T_ABSTRACT) {
        // if not an abstract class and not having an explicit constructor,
        // adds a default constructor
        outputJavaFFIConstructor(cgCls, ar, cons);
      }

      if (m_stmt) m_stmt->outputCPP(cgCls, ar);
      cgCls.indentEnd("}\n");

      fcls.close();
    }
    break;
  case CodeGenerator::JavaFFICppDecl:
  case CodeGenerator::JavaFFICppImpl:
    {
      if (classScope->isRedeclaring()) break;

      if (m_stmt) m_stmt->outputCPP(cg, ar);
      FunctionScopePtr cons = classScope->findConstructor(ar, true);
      if (cons && !cons->isAbstract() || m_type != T_ABSTRACT) {
        outputJavaFFICPPCreator(cg, ar, cons);
      }
    }
    break;
  default:
    ASSERT(false);
    break;
  }

  ar->popScope();
}
예제 #22
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();
}
예제 #23
0
void InterfaceStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  ClassScopePtr classScope = m_classScope.lock();
  if (cg.getContext() == CodeGenerator::NoContext) {
    if (classScope->isVolatile()) {
      cg.printf("g->CDEC(%s) = true;\n", m_name.c_str());
    }
    return;
  }

  ar->pushScope(classScope);
  string clsNameStr = classScope->getId();
  const char *clsName = clsNameStr.c_str();

  switch (cg.getContext()) {
  case CodeGenerator::CppForwardDeclaration:
    if (Option::GenerateCPPMacros) {
      cg.printf("FORWARD_DECLARE_CLASS(%s);\n", clsName);
    }
    break;
  case CodeGenerator::CppDeclaration:
    {
      printSource(cg);
      cg.printf("class %s%s", Option::ClassPrefix, clsName);
      cg.indentBegin(" {\n");
      if (m_stmt) m_stmt->outputCPP(cg, ar);
      cg.indentEnd("};\n");
    }
    break;
  case CodeGenerator::CppImplementation:
    // do nothing
    break;
  case CodeGenerator::CppFFIDecl:
  case CodeGenerator::CppFFIImpl:
    // do nothing
    break;
  case CodeGenerator::JavaFFI:
    {
      // TODO support PHP namespaces, once HPHP supports it
      string packageName = Option::JavaFFIRootPackage;
      string packageDir = packageName;
      Util::replaceAll(packageDir, ".", "/");

      string outputDir = ar->getOutputPath() + "/" + Option::FFIFilePrefix +
        packageDir + "/";
      Util::mkdir(outputDir);

      // uses a different cg to generate a separate file for each PHP class
      string clsFile = outputDir + getOriginalName() + ".java";
      ofstream fcls(clsFile.c_str());
      CodeGenerator cgCls(&fcls, CodeGenerator::FileCPP);
      cgCls.setContext(CodeGenerator::JavaFFIInterface);

      cgCls.printf("package %s;\n\n", packageName.c_str());
      cgCls.printf("import hphp.*;\n\n");

      cgCls.printf("public interface %s", getOriginalName().c_str());
      if (m_base) {
        bool first = true;
        for (int i = 0; i < m_base->getCount(); i++) {
          ScalarExpressionPtr exp =
            dynamic_pointer_cast<ScalarExpression>((*m_base)[i]);
          const char *intf = exp->getString().c_str();
          ClassScopePtr intfClassScope = ar->findClass(intf);
          if (intfClassScope && classScope->derivesFrom(ar, intf, false, false)
           && intfClassScope->isUserClass()) {
            if (first) {
              cgCls.printf(" extends ");
              first = false;
            }
            else {
              cgCls.printf(", ");
            }
            cgCls.printf(intfClassScope->getOriginalName());
          }
        }
      }

      cgCls.indentBegin(" {\n");
      if (m_stmt) m_stmt->outputCPP(cgCls, ar);
      cgCls.indentEnd("}\n");

      fcls.close();
    }
    break;
  case CodeGenerator::JavaFFICppDecl:
  case CodeGenerator::JavaFFICppImpl:
    // do nothing
    break;
  default:
    ASSERT(false);
    break;
  }

  ar->popScope();
}
예제 #24
0
void FunctionStatement::outputCPPImpl(CodeGenerator &cg,
                                      AnalysisResultPtr ar) {
  CodeGenerator::Context context = cg.getContext();

  FunctionScopePtr funcScope = m_funcScope.lock();
  string fname = funcScope->getId(cg).c_str();
  bool pseudoMain = funcScope->inPseudoMain();
  string origFuncName = !pseudoMain ? funcScope->getOriginalName() :
          ("run_init::" + funcScope->getFileScope()->getName());
  string funcSection;

  if (outputFFI(cg, ar)) return;

  if (context == CodeGenerator::NoContext) {
    string rname = cg.formatLabel(m_name);
    if (funcScope->isRedeclaring()) {
      cg.printf("g->%s%s = &%s%s;\n", Option::CallInfoPrefix, m_name.c_str(),
          Option::CallInfoPrefix, fname.c_str());
    }
    if (funcScope->isVolatile()) {
      cg_printf("g->declareFunctionLit(");
      cg_printString(m_name, ar);
      cg_printf(");\n");
      cg_printf("g->FVF(%s) = true;\n", rname.c_str());
    }
    return;
  }

  if (context == CodeGenerator::CppDeclaration &&
      !funcScope->isInlined()) return;

  if (context == CodeGenerator::CppPseudoMain &&
      !pseudoMain) return;
  if (context == CodeGenerator::CppImplementation &&
      (funcScope->isInlined() || pseudoMain)) return;
  ar->pushScope(funcScope);

  cg.setPHPLineNo(-1);

  if (pseudoMain && !Option::GenerateCPPMain) {
    if (context == CodeGenerator::CppPseudoMain) {
      if (cg.getOutput() != CodeGenerator::SystemCPP) {
        cg.setContext(CodeGenerator::NoContext); // no inner functions/classes
        funcScope->getVariables()->setAttribute(VariableTable::ForceGlobal);
        outputCPPStmt(cg, ar);
        funcScope->getVariables()->clearAttribute(VariableTable::ForceGlobal);
        cg.setContext(CodeGenerator::CppPseudoMain);
        ar->popScope();
        return;
      }
    } else if (context == CodeGenerator::CppForwardDeclaration &&
               cg.getOutput() != CodeGenerator::SystemCPP) {
      return;
    }
  }

  if (context == CodeGenerator::CppImplementation) {
    printSource(cg);
  } else if (context == CodeGenerator::CppForwardDeclaration &&
             Option::GenerateCppLibCode) {
    cg_printf("\n");
    printSource(cg);
    cg.printDocComment(funcScope->getDocComment());
  }

  if (funcScope->isInlined()) cg_printf("inline ");

  TypePtr type = funcScope->getReturnType();
  if (type) {
    type->outputCPPDecl(cg, ar);
  } else {
    cg_printf("void");
  }

  funcSection = Option::FunctionSections[origFuncName];
  if (!funcSection.empty()) {
    cg_printf(" __attribute__ ((section (\".text.%s\")))",
              funcSection.c_str());
  }

  if (pseudoMain) {
    cg_printf(" %s%s(", Option::PseudoMainPrefix,
              funcScope->getFileScope()->pseudoMainName().c_str());
  } else {
    cg_printf(" %s%s(", Option::FunctionPrefix, fname.c_str());
  }

  switch (context) {
  case CodeGenerator::CppForwardDeclaration:
    funcScope->outputCPPParamsDecl(cg, ar, m_params, true);
    cg_printf(");\n");
    if (funcScope->hasDirectInvoke()) {
      cg_printf("Variant %s%s(void *extra, CArrRef params);\n",
                Option::InvokePrefix, fname.c_str());
    }
    break;
  case CodeGenerator::CppDeclaration:
  case CodeGenerator::CppImplementation:
  case CodeGenerator::CppPseudoMain:
    {
      funcScope->outputCPPParamsDecl(cg, ar, m_params, false);
      cg_indentBegin(") {\n");
      const char *sys =
        (cg.getOutput() == CodeGenerator::SystemCPP ? "_BUILTIN" : "");
      if (pseudoMain) {
        cg_printf("PSEUDOMAIN_INJECTION%s(%s, %s%s);\n",
                  sys, origFuncName.c_str(), Option::PseudoMainPrefix,
                  funcScope->getFileScope()->pseudoMainName().c_str());
      } else {
        if (m_stmt->hasBody()) {
          cg_printf("FUNCTION_INJECTION%s(%s);\n", sys, origFuncName.c_str());
        }
        outputCPPArgInjections(cg, ar, origFuncName.c_str(), ClassScopePtr(),
                               funcScope);
      }
      funcScope->outputCPP(cg, ar);
      cg.setContext(CodeGenerator::NoContext); // no inner functions/classes
      outputCPPStmt(cg, ar);
      cg.setContext(context);
      cg_indentEnd("} /* function */\n");
    }
    break;
  default:
    ASSERT(false);
  }

  ar->popScope();
}