Exemplo n.º 1
0
void ClassVariable::analyzeProgramImpl(AnalysisResultPtr ar) {
  m_declaration->analyzeProgram(ar);
  AnalysisResult::Phase phase = ar->getPhase();
  if (phase != AnalysisResult::AnalyzeAll) {
    return;
  }
  ClassScopePtr scope = 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);
      scope->getVariables()->markOverride(ar, var->getName());
    } else {
      SimpleVariablePtr var =
        dynamic_pointer_cast<SimpleVariable>(exp);
      scope->getVariables()->markOverride(ar, var->getName());
      scope->getVariables()->setClassInitVal(var->getName(),
                                             makeConstant(ar, "null"));
    }
  }
}
Exemplo n.º 2
0
void ClassVariable::inferTypes(AnalysisResultPtr ar) {
  ASSERT(getScope().get() == getClassScope().get());
  IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope());

  m_declaration->inferAndCheck(ar, Type::Variant, false);

  if (m_modifiers->isStatic()) {
    ClassScopePtr scope = 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);
        // 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(),
                                                VariableTable::AnyVars);
          }
        }
        ExpressionPtr value = assignment->getValue();
        if (value->containsDynamicConstant(ar)) {
          scope->getVariables()->
            setAttribute(VariableTable::ContainsDynamicStatic);
        }
      }
    }
  }
}
Exemplo n.º 3
0
void ClassVariable::analyzeProgram(AnalysisResultPtr ar) {
  m_declaration->analyzeProgram(ar);
  AnalysisResult::Phase phase = ar->getPhase();
  if (phase != AnalysisResult::AnalyzeAll) {
    return;
  }
  if (m_modifiers->isAbstract()) {
    Compiler::Error(Compiler::AbstractProperty, shared_from_this());
  }
  ClassScopePtr scope = getClassScope();
  for (int i = 0; i < m_declaration->getCount(); i++) {
    ExpressionPtr exp = (*m_declaration)[i];
    bool error;
    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);
      error = scope->getVariables()->markOverride(ar, var->getName());
    } else {
      SimpleVariablePtr var =
        dynamic_pointer_cast<SimpleVariable>(exp);
      error = scope->getVariables()->markOverride(ar, var->getName());
      scope->getVariables()->setClassInitVal(var->getName(),
                                             makeConstant(ar, "null"));
    }
    if (error) {
      Compiler::Error(Compiler::InvalidOverride, exp);
    }
  }
}
bool ObjectPropertyExpression::isNonPrivate(AnalysisResultPtr ar) {
    // To tell whether a property is declared as private in the context
    ClassScopePtr cls = getOriginalClass();
    if (!cls || !cls->getVariables()->hasNonStaticPrivate()) return true;
    if (m_property->getKindOf() != Expression::KindOfScalarExpression) {
        return false;
    }
    ScalarExpressionPtr name =
        dynamic_pointer_cast<ScalarExpression>(m_property);
    string propName = name->getString();
    Symbol *sym = cls->getVariables()->getSymbol(propName);
    if (!sym || sym->isStatic() || !sym->isPrivate()) return true;
    return false;
}
Exemplo n.º 5
0
void ClassVariable::inferTypes(AnalysisResultPtr ar) {
  assert(getScope().get() == getClassScope().get());
  IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope());

  // assignments will ignore the passed in type,
  // but we need to ensure that Null is applied to
  // the simple variables.
  m_declaration->inferAndCheck(ar, Type::Null, false);

  if (m_modifiers->isStatic()) {
    ClassScopePtr scope = getClassScope();
    for (int i = 0; i < m_declaration->getCount(); i++) {
      ExpressionPtr exp = (*m_declaration)[i];
      SimpleVariablePtr var;
      if (exp->is(Expression::KindOfAssignmentExpression)) {
        AssignmentExpressionPtr assignment =
          dynamic_pointer_cast<AssignmentExpression>(exp);
        ExpressionPtr value = assignment->getValue();
        if (value->containsDynamicConstant(ar)) {
          scope->getVariables()->
            setAttribute(VariableTable::ContainsDynamicStatic);
        }
      }
    }
  }
}
Exemplo n.º 6
0
void AnalysisResult::forceClassVariants(
    const std::string &name,
    ClassScopePtr curScope,
    bool doStatic,
    bool acquireLocks /* = false */) {
  if (curScope) {
    COND_TRY_LOCK(curScope, acquireLocks);
    curScope->getVariables()->forceVariant(
      shared_from_this(), name, VariableTable::GetVarClassMask(true, doStatic));
  }

  ConditionalLock lock(getMutex(), acquireLocks);
  if (m_classForcedVariants[doStatic]) {
    return;
  }

  AnalysisResultPtr ar = shared_from_this();
  for (StringToClassScopePtrVecMap::const_iterator iter = m_classDecs.begin();
       iter != m_classDecs.end(); ++iter) {
    for (ClassScopePtr cls: iter->second) {
      COND_TRY_LOCK(cls, acquireLocks);
      cls->getVariables()->forceVariant(
        ar, name, VariableTable::GetVarClassMask(false, doStatic));
    }
  }
}
Exemplo n.º 7
0
void ClassVariable::onParseRecur(AnalysisResultConstPtr ar,
                                 ClassScopePtr scope) {
  ModifierExpressionPtr modifiers =
    scope->setModifiers(m_modifiers);

  for (int i = 0; i < m_declaration->getCount(); i++) {
    VariableTablePtr variables = scope->getVariables();
    ExpressionPtr exp = (*m_declaration)[i];
    if (exp->is(Expression::KindOfAssignmentExpression)) {
      AssignmentExpressionPtr assignment =
        dynamic_pointer_cast<AssignmentExpression>(exp);
      ExpressionPtr var = assignment->getVariable();
      const std::string &name =
        dynamic_pointer_cast<SimpleVariable>(var)->getName();
      if (variables->isPresent(name)) {
        Compiler::Error(Compiler::DeclaredVariableTwice, exp);
        m_declaration->removeElement(i--);
      } else {
        assignment->onParseRecur(ar, scope);
      }
    } else {
      const std::string &name =
        dynamic_pointer_cast<SimpleVariable>(exp)->getName();
      if (variables->isPresent(name)) {
        Compiler::Error(Compiler::DeclaredVariableTwice, exp);
        m_declaration->removeElement(i--);
      } else {
        variables->add(name, Type::Variant, false, ar, exp, m_modifiers);
      }
    }
  }

  scope->setModifiers(modifiers);
}
Exemplo n.º 8
0
void VariableTable::forceVariants(AnalysisResultConstPtr ar, int varClass,
                                  bool recur /* = true */) {
  int mask = varClass & ~m_forcedVariants;
  if (mask) {
    if (!m_hasPrivate) mask &= ~AnyPrivateVars;
    if (!m_hasStatic) mask &= ~AnyStaticVars;

    if (mask) {
      for (unsigned int i = 0; i < m_symbolVec.size(); i++) {
        Symbol *sym = m_symbolVec[i];
        if (!sym->isHidden() && sym->declarationSet() &&
            mask & GetVarClassMaskForSym(sym)) {
          setType(ar, sym, Type::Variant, true);
          sym->setIndirectAltered();
        }
      }
    }
    m_forcedVariants |= varClass;

    if (recur) {
      ClassScopePtr parent = m_blockScope.getParentScope(ar);
      if (parent && !parent->isRedeclaring()) {
        parent->getVariables()->forceVariants(ar, varClass & ~AnyPrivateVars);
      }
    }
  }
}
void AssignmentExpression::onParseRecur(AnalysisResultConstPtr ar,
                                        ClassScopePtr scope) {
  // This is that much we can do during parse phase.
  TypePtr type;
  if (m_value->is(Expression::KindOfScalarExpression)) {
    type = static_pointer_cast<ScalarExpression>(m_value)->inferenceImpl(
      ar, 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 = 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);
  } 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
  }
}
Exemplo n.º 10
0
void AssignmentExpression::onParseRecur(AnalysisResultConstPtr ar,
                                        FileScopeRawPtr fs,
                                        ClassScopePtr scope) {
    auto isArray = false;
    if (m_value->is(Expression::KindOfUnaryOpExpression)) {
        auto uexp = dynamic_pointer_cast<UnaryOpExpression>(m_value);
        if (uexp->getOp() == T_ARRAY) {
            isArray = true;
        }
    }

    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.
        if (isArray) {
            parseTimeFatal(fs,
                           Compiler::NoError,
                           "Arrays are not allowed in class constants");
        }
        auto exp = dynamic_pointer_cast<ConstantExpression>(m_variable);
        scope->getConstants()->add(exp->getName(), m_value, ar, m_variable);
    } else if (m_variable->is(Expression::KindOfSimpleVariable)) {
        auto var = dynamic_pointer_cast<SimpleVariable>(m_variable);
        scope->getVariables()->add(var->getName(), true, ar,
                                   shared_from_this(), scope->getModifiers());
        var->clearContext(Declaration); // to avoid wrong CodeError
    } else {
        assert(false); // parse phase shouldn't handle anything else
    }
}
Exemplo n.º 11
0
void ClassVariable::getCtorAndInitInfo(
    ExpressionPtr exp,
    bool &needsCppCtor,
    bool &needsInit,
    SimpleVariablePtr &var,
    TypePtr &type,
    Symbol *&sym,
    ExpressionPtr &value) {

  ClassScopePtr scope = getClassScope();
  bool derivFromRedec = scope->derivesFromRedeclaring() &&
    !m_modifiers->isPrivate();
  AssignmentExpressionPtr assignment;
  bool isAssign = exp->is(Expression::KindOfAssignmentExpression);
  if (isAssign) {
    assignment = static_pointer_cast<AssignmentExpression>(exp);
    var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable());
    ASSERT(var);
    value = assignment->getValue();
    ASSERT(value);
  } else {
    var = dynamic_pointer_cast<SimpleVariable>(exp);
    ASSERT(var);
  }
  sym = scope->getVariables()->getSymbol(var->getName());
  ASSERT(sym);
  type = scope->getVariables()->getFinalType(var->getName());
  ASSERT(type);

  bool isValueNull = isAssign ? value->isLiteralNull() : false;
  bool typeIsInitable = type->is(Type::KindOfVariant) ||
                        type->getCPPInitializer();
  if (!derivFromRedec &&
      !sym->isOverride() &&
      (isAssign ?
        (isValueNull ||
         (value->is(Expression::KindOfScalarExpression) &&
          type->isPrimitive())) :
        typeIsInitable)) {
    needsCppCtor = true;
  } else if (isAssign || typeIsInitable) {
    // if we aren't an assignment and the type is not a variant
    // w/ no CPP initializer, then we currently don't bother
    // to initialize it in init().
    needsInit = true;
  }
}
Exemplo n.º 12
0
void ClassVariable::addTraitPropsToScope(AnalysisResultPtr ar,
                                         ClassScopePtr scope) {
  ModifierExpressionPtr modifiers = scope->setModifiers(m_modifiers);
  VariableTablePtr variables = scope->getVariables();

  for (int i = 0; i < m_declaration->getCount(); i++) {
    ExpressionPtr exp = (*m_declaration)[i];

    SimpleVariablePtr var;
    ExpressionPtr value;
    if (exp->is(Expression::KindOfAssignmentExpression)) {
      AssignmentExpressionPtr assignment =
        dynamic_pointer_cast<AssignmentExpression>(exp);
      var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable());
      value = assignment->getValue();
    } else {
      var = dynamic_pointer_cast<SimpleVariable>(exp);
      value = makeConstant(ar, "null");
    }

    const string &name = var->getName();
    Symbol *sym;
    ClassScopePtr prevScope = variables->isPresent(name) ? scope :
      scope->getVariables()->findParent(ar, name, sym);

    if (prevScope &&
        !isEquivRedecl(name, exp, m_modifiers,
                       prevScope->getVariables()->getSymbol(name))) {
      Compiler::Error(Compiler::DeclaredVariableTwice, exp);
      m_declaration->removeElement(i--);
    } else {
      if (prevScope != scope) { // Property is new or override, so add it
        variables->add(name, Type::Variant, false, ar, exp, m_modifiers);
        variables->getSymbol(name)->setValue(exp);
        variables->setClassInitVal(name, value);
        variables->markOverride(ar, name);
      } else {
        m_declaration->removeElement(i--);
      }
    }
  }
  scope->setModifiers(modifiers);
}
Exemplo n.º 13
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();
      }
    }
  }
}
Exemplo n.º 14
0
TypePtr VariableTable::checkProperty(BlockScopeRawPtr context,
                                     Symbol *sym, TypePtr type,
                                     bool coerce, AnalysisResultConstPtr ar) {
  always_assert(sym->isPresent());
  if (sym->isOverride()) {
    Symbol *base;
    ClassScopePtr parent = findParent(ar, sym->getName(), base);
    assert(parent);
    assert(parent.get() != &m_blockScope);
    assert(base && !base->isPrivate());
    if (context->is(BlockScope::FunctionScope)) {
      GET_LOCK(parent);
      type = parent->getVariables()->setType(ar, base, type, coerce);
    } else {
      TRY_LOCK(parent);
      type = parent->getVariables()->setType(ar, base, type, coerce);
    }
  }
  return setType(ar, sym, type, coerce);
}
Exemplo n.º 15
0
ClassScopePtr VariableTable::findParent(AnalysisResultConstPtr ar,
                                        const string &name,
                                        const Symbol *&sym) const {
  sym = nullptr;
  for (ClassScopePtr parent = m_blockScope.getParentScope(ar);
       parent && !parent->isRedeclaring();
       parent = parent->getParentScope(ar)) {
    sym = parent->getVariables()->getSymbol(name);
    assert(!sym || sym->isPresent());
    if (sym) return parent;
  }
  return ClassScopePtr();
}
Exemplo n.º 16
0
StatementPtr ClassVariable::preOptimize(AnalysisResultConstPtr ar) {
  ClassScopePtr scope = 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);
    }
  }
  return StatementPtr();
}
Exemplo n.º 17
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);
    }
  }
}
Exemplo n.º 18
0
void ClassVariable::onParseRecur(AnalysisResultConstPtr ar,
                                 ClassScopePtr scope) {
  ModifierExpressionPtr modifiers =
    scope->setModifiers(m_modifiers);

  if (m_modifiers->isAbstract()) {
    parseTimeFatal(Compiler::InvalidAttribute,
                   "Properties cannot be declared abstract");
  }

  if (m_modifiers->isFinal()) {
    parseTimeFatal(Compiler::InvalidAttribute,
                   "Properties cannot be declared final");
  }

  for (int i = 0; i < m_declaration->getCount(); i++) {
    VariableTablePtr variables = scope->getVariables();
    ExpressionPtr exp = (*m_declaration)[i];
    if (exp->is(Expression::KindOfAssignmentExpression)) {
      AssignmentExpressionPtr assignment =
        dynamic_pointer_cast<AssignmentExpression>(exp);
      ExpressionPtr var = assignment->getVariable();
      const std::string &name =
        dynamic_pointer_cast<SimpleVariable>(var)->getName();
      if (variables->isPresent(name)) {
        exp->parseTimeFatal(Compiler::DeclaredVariableTwice,
                            "Cannot redeclare %s::$%s",
                            scope->getOriginalName().c_str(), name.c_str());
      } else {
        assignment->onParseRecur(ar, scope);
      }
    } else {
      const std::string &name =
        dynamic_pointer_cast<SimpleVariable>(exp)->getName();
      if (variables->isPresent(name)) {
        exp->parseTimeFatal(Compiler::DeclaredVariableTwice,
                            "Cannot redeclare %s::$%s",
                            scope->getOriginalName().c_str(), name.c_str());
      } else {
        variables->add(name, Type::Null, false, ar, exp, m_modifiers);
      }
    }
  }

  scope->setModifiers(modifiers);
}
Exemplo n.º 19
0
bool AnalysisResult::declareClass(ClassScopePtr classScope) const {
  assert(m_phase < AnalyzeAll);

  string cname = classScope->getName();
  // System classes override
  if (m_systemClasses.find(cname) != m_systemClasses.end()) {
    // we need someone to hold on to a reference to it
    // even though we're not going to do anything with it
    this->lock()->m_ignoredScopes.push_back(classScope);
    return false;
  }

  int mask =
    (m_classForcedVariants[0] ? VariableTable::NonPrivateNonStaticVars : 0) |
    (m_classForcedVariants[1] ? VariableTable::NonPrivateStaticVars : 0);

  if (mask) {
    AnalysisResultConstPtr ar = shared_from_this();
    classScope->getVariables()->forceVariants(ar, mask);
  }
  return true;
}
Exemplo n.º 20
0
bool Option::Load(const char *filename) {
  ASSERT(filename && *filename);
  try {
    Scanner scanner(new ylmm::basic_buffer(filename), true, false);
    Logger::Info("loading options from %s...", filename);
    AnalysisResultPtr ar(new AnalysisResult());

    struct stat sb;
    if (stat(filename, &sb)) {
      Logger::Error("Unable to stat file %s", filename);
      return false;
    }
    ParserPtr parser(new Parser(scanner, filename, sb.st_size, ar));
    if (parser->parse()) {
      Logger::Error("Unable to parse file: %s\n%s", filename,
                    parser->getMessage().c_str());
      return false;
    }

    FileScopePtr file = ar->findFileScope(filename, false);
    ClassScopePtr cls = file->getClass("hphpoption");
    if (!cls) {
      Logger::Error("Unable to find HPHPOption class in %s", filename);
      return false;
    }

    if (!Load(cls->getVariables())) {
      return false;
    }

  } catch (std::runtime_error) {
    Logger::Error("Unable to open file %s", filename);
    return false;
  }
  return true;
}
Exemplo n.º 21
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();
}
Exemplo n.º 22
0
void ClassStatement::outputCPPClassDecl(CodeGenerator &cg,
                                        AnalysisResultPtr ar,
                                        const char *clsName,
                                        const char *originalName,
                                        const char *parent) {
  ClassScopePtr classScope = m_classScope.lock();
  VariableTablePtr variables = classScope->getVariables();
  ConstantTablePtr constants = classScope->getConstants();
  if (variables->hasAllJumpTables() && constants->hasJumpTable() &&
      classScope->hasAllJumpTables()) {
    cg_printf("DECLARE_CLASS(%s, %s, %s)\n", clsName, originalName, parent);
    return;
  }

  // Now we start to break down DECLARE_CLASS into lines of code that could
  // be generated differently...

  cg_printf("DECLARE_CLASS_COMMON(%s, %s)\n", clsName, originalName);
  cg_printf("DECLARE_INVOKE_EX(%s, %s, %s)\n",
            clsName, originalName, parent);

  cg.printSection("DECLARE_STATIC_PROP_OPS");
  cg_printf("public:\n");
  if (classScope->needStaticInitializer()) {
    cg_printf("static void os_static_initializer();\n");
  }
  if (variables->hasJumpTable(VariableTable::JumpTableClassStaticGetInit)) {
    cg_printf("static Variant os_getInit(const char *s, int64 hash);\n");
  } else {
    cg_printf("#define OMIT_JUMP_TABLE_CLASS_STATIC_GETINIT_%s 1\n", clsName);
  }
  if (variables->hasJumpTable(VariableTable::JumpTableClassStaticGet)) {
    cg_printf("static Variant os_get(const char *s, int64 hash);\n");
  } else {
    cg_printf("#define OMIT_JUMP_TABLE_CLASS_STATIC_GET_%s 1\n", clsName);
  }
  if (variables->hasJumpTable(VariableTable::JumpTableClassStaticLval)) {
    cg_printf("static Variant &os_lval(const char *s, int64 hash);\n");
  } else {
    cg_printf("#define OMIT_JUMP_TABLE_CLASS_STATIC_LVAL_%s 1\n", clsName);
  }
  if (constants->hasJumpTable()) {
    cg_printf("static Variant os_constant(const char *s);\n");
  } else {
    cg_printf("#define OMIT_JUMP_TABLE_CLASS_CONSTANT_%s 1\n", clsName);
  }

  cg.printSection("DECLARE_INSTANCE_PROP_OPS");
  cg_printf("public:\n");
  cg_printf("virtual bool o_exists(CStrRef s, int64 hash,\n");
  cg_printf("                      const char *context = NULL) const;\n");
  cg_printf("bool o_existsPrivate(CStrRef s, int64 hash) const;\n");
  cg_printf("virtual void o_get(Array &props) const;\n");
  cg_printf("virtual Variant o_get(CStrRef s, int64 hash, "
            "bool error = true,\n");
  cg_printf("                      const char *context = NULL);\n");
  cg_printf("Variant o_getPrivate(CStrRef s, int64 hash, "
            "bool error = true);\n");
  cg_printf("virtual Variant o_set(CStrRef s, int64 hash, CVarRef v,\n");
  cg_printf("                      bool forInit = false,\n");
  cg_printf("                      const char *context = NULL);\n");
  cg_printf("Variant o_setPrivate(CStrRef s, int64 hash, CVarRef v, "
            "bool forInit);\n");
  cg_printf("virtual Variant &o_lval(CStrRef s, int64 hash,\n");
  cg_printf("                        const char *context = NULL);\n");
  cg_printf("Variant &o_lvalPrivate(CStrRef s, int64 hash);\n");

  cg.printSection("DECLARE_INSTANCE_PUBLIC_PROP_OPS");
  cg_printf("public:\n");
  if (variables->hasJumpTable(VariableTable::JumpTableClassExistsPublic)) {
    cg_printf("virtual bool o_existsPublic(CStrRef s, int64 hash) const;\n");
  } else {
    cg_printf("#define OMIT_JUMP_TABLE_CLASS_exists_PUBLIC_%s 1\n", clsName);
  }
  if (variables->hasJumpTable(VariableTable::JumpTableClassGetPublic)) {
    cg_printf("virtual Variant o_getPublic(CStrRef s, int64 hash,\n");
    cg_printf("                            bool error = true);\n");
  } else {
    cg_printf("#define OMIT_JUMP_TABLE_CLASS_get_PUBLIC_%s 1\n", clsName);
  }
  if (variables->hasJumpTable(VariableTable::JumpTableClassSetPublic)) {
    cg_printf("virtual Variant o_setPublic(CStrRef s, int64 hash,\n");
    cg_printf("                            CVarRef v, bool forInit);\n");
  } else {
    cg_printf("#define OMIT_JUMP_TABLE_CLASS_set_PUBLIC_%s 1\n", clsName);
  }
  if (variables->hasJumpTable(VariableTable::JumpTableClassLvalPublic)) {
    cg_printf("virtual Variant &o_lvalPublic(CStrRef s, int64 hash);\n");
  } else {
    cg_printf("#define OMIT_JUMP_TABLE_CLASS_lval_PUBLIC_%s 1\n", clsName);
  }

  cg.printSection("DECLARE_COMMON_INVOKE");
  if (classScope->hasJumpTable(ClassScope::JumpTableStaticInvoke)) {
    cg_printf("static Variant os_invoke(const char *c, const char *s,\n");
    cg_printf("                         CArrRef ps, int64 h, "
              "bool f = true);\n");
  } else {
    cg_printf("#define OMIT_JUMP_TABLE_CLASS_STATIC_INVOKE_%s 1\n", clsName);
  }
  if (classScope->hasJumpTable(ClassScope::JumpTableInvoke)) {
    cg_printf("virtual Variant o_invoke(const char *s, CArrRef ps, "
              "int64 h,\n");
    cg_printf("                         bool f = true);\n");
    cg_printf("virtual Variant o_invoke_few_args(const char *s, int64 h,\n");
    cg_printf("                                  int count,\n");
    cg_printf("                                  "
              "INVOKE_FEW_ARGS_DECL_ARGS);\n");
  } else {
    cg_printf("#define OMIT_JUMP_TABLE_CLASS_INVOKE_%s 1\n", clsName);
  }

  cg_printf("\n");
  cg_printf("public:\n");
}
Exemplo n.º 23
0
bool ClassStatement::hasImpl() const {
  ClassScopePtr cls = m_classScope.lock();
  return cls->isVolatile() ||
    cls->getVariables()->getAttribute(VariableTable::ContainsDynamicStatic);
}
Exemplo n.º 24
0
void ClassVariable::onParseRecur(AnalysisResultConstRawPtr ar,
                                 FileScopeRawPtr fs,
                                 ClassScopePtr scope) {
  ModifierExpressionPtr modifiers =
    scope->setModifiers(m_modifiers);

  if (m_modifiers->isAbstract()) {
    m_modifiers->parseTimeFatal(fs,
                                Compiler::InvalidAttribute,
                                "Properties cannot be declared abstract");
  }

  if (m_modifiers->isFinal()) {
    m_modifiers->parseTimeFatal(fs,
                                Compiler::InvalidAttribute,
                                "Properties cannot be declared final");
  }

  if (!m_modifiers->isStatic() && scope->isStaticUtil()) {
    m_modifiers->parseTimeFatal(
      fs,
      Compiler::InvalidAttribute,
      "Class %s contains non-static property declaration and "
      "therefore cannot be declared 'abstract final'",
      scope->getOriginalName().c_str()
    );
  }

  if ((m_modifiers->isExplicitlyPublic() +
       m_modifiers->isProtected() +
       m_modifiers->isPrivate()) > 1) {
    m_modifiers->parseTimeFatal(
      fs,
      Compiler::InvalidAttribute,
      "%s: properties of %s",
      Strings::PICK_ACCESS_MODIFIER,
      scope->getOriginalName().c_str()
    );
  }

  for (int i = 0; i < m_declaration->getCount(); i++) {
    VariableTablePtr variables = scope->getVariables();
    ExpressionPtr exp = (*m_declaration)[i];
    if (exp->is(Expression::KindOfAssignmentExpression)) {
      auto assignment = dynamic_pointer_cast<AssignmentExpression>(exp);
      ExpressionPtr var = assignment->getVariable();
      const auto& name =
        dynamic_pointer_cast<SimpleVariable>(var)->getName();
      if (variables->isPresent(name)) {
        exp->parseTimeFatal(fs,
                            Compiler::DeclaredVariableTwice,
                            "Cannot redeclare %s::$%s",
                            scope->getOriginalName().c_str(), name.c_str());
      } else {
        assignment->onParseRecur(ar, fs, scope);
      }
    } else {
      const std::string &name =
        dynamic_pointer_cast<SimpleVariable>(exp)->getName();
      if (variables->isPresent(name)) {
        exp->parseTimeFatal(fs,
                            Compiler::DeclaredVariableTwice,
                            "Cannot redeclare %s::$%s",
                            scope->getOriginalName().c_str(), name.c_str());
      } else {
        variables->add(name, false, ar, exp, m_modifiers);
      }
    }
  }

  scope->setModifiers(modifiers);
}
Exemplo n.º 25
0
void ClassStatement::outputCPPClassDecl(CodeGenerator &cg,
                                        AnalysisResultPtr ar,
                                        const char *clsName,
                                        const char *originalName,
                                        const char *parent) {
  ClassScopePtr classScope = m_classScope.lock();
  VariableTablePtr variables = classScope->getVariables();
  ConstantTablePtr constants = classScope->getConstants();
  if (variables->hasAllJumpTables() && constants->hasJumpTable() &&
      classScope->hasAllJumpTables()) {
    cg_printf("DECLARE_CLASS(%s, %s, %s)\n", clsName, originalName, parent);
    return;
  }

  // Now we start to break down DECLARE_CLASS into lines of code that could
  // be generated differently...

  cg_printf("DECLARE_CLASS_COMMON(%s, %s)\n", clsName, originalName);
  cg_printf("DECLARE_INVOKE_EX(%s, %s, %s)\n",
            clsName, originalName, parent);

  cg.printSection("DECLARE_STATIC_PROP_OPS");
  cg_printf("public:\n");
  if (classScope->needStaticInitializer()) {
    cg_printf("static void os_static_initializer();\n");
  }
  if (variables->hasJumpTable(VariableTable::JumpTableClassStaticGetInit)) {
    cg_printf("static Variant os_getInit(CStrRef s);\n");
  } else {
    cg_printf("#define OMIT_JUMP_TABLE_CLASS_STATIC_GETINIT_%s 1\n", clsName);
  }
  if (variables->hasJumpTable(VariableTable::JumpTableClassStaticGet)) {
    cg_printf("static Variant os_get(CStrRef s);\n");
  } else {
    cg_printf("#define OMIT_JUMP_TABLE_CLASS_STATIC_GET_%s 1\n", clsName);
  }
  if (variables->hasJumpTable(VariableTable::JumpTableClassStaticLval)) {
    cg_printf("static Variant &os_lval(CStrRef s);\n");
  } else {
    cg_printf("#define OMIT_JUMP_TABLE_CLASS_STATIC_LVAL_%s 1\n", clsName);
  }
  if (constants->hasJumpTable()) {
    cg_printf("static Variant os_constant(const char *s);\n");
  } else {
    cg_printf("#define OMIT_JUMP_TABLE_CLASS_CONSTANT_%s 1\n", clsName);
  }

  cg.printSection("DECLARE_INSTANCE_PROP_OPS");
  cg_printf("public:\n");

  if (variables->hasJumpTable(VariableTable::JumpTableClassGetArray)) {
    cg_printf("virtual void o_getArray(Array &props) const;\n");
  } else {
    cg_printf("#define OMIT_JUMP_TABLE_CLASS_GETARRAY_%s 1\n", clsName);
  }
  if (variables->hasJumpTable(VariableTable::JumpTableClassSetArray)) {
    cg_printf("virtual void o_setArray(CArrRef props);\n");
  } else {
    cg_printf("#define OMIT_JUMP_TABLE_CLASS_SETARRAY_%s 1\n", clsName);
  }

  if (variables->hasJumpTable(VariableTable::JumpTableClassRealProp)) {
    cg_printf("virtual Variant *o_realProp(CStrRef s, int flags,\n");
    cg_printf("                            CStrRef context = null_string) "
              "const;\n");
  } else {
    cg_printf("#define OMIT_JUMP_TABLE_CLASS_realProp_%s 1\n", clsName);
  }
  if (variables->hasNonStaticPrivate()) {
    cg_printf("Variant *o_realPropPrivate(CStrRef s, int flags) const;\n");
  } else {
    cg_printf("#define OMIT_JUMP_TABLE_CLASS_realProp_PRIVATE_%s 1\n", clsName);
  }

  cg.printSection("DECLARE_INSTANCE_PUBLIC_PROP_OPS");
  cg_printf("public:\n");
  if (variables->hasJumpTable(VariableTable::JumpTableClassRealPropPublic)) {
    cg_printf("virtual Variant *o_realPropPublic(CStrRef s, "
              "int flags) const;\n");
  } else {
    cg_printf("#define OMIT_JUMP_TABLE_CLASS_realProp_PUBLIC_%s 1\n", clsName);
  }

  cg.printSection("DECLARE_COMMON_INVOKE");
  if (classScope->hasJumpTable(ClassScope::JumpTableStaticInvoke)) {
    cg_printf("static Variant os_invoke(const char *c, "
              "MethodIndex methodIndex,\n");
    cg_printf("                         const char *s, CArrRef ps, int64 h, "
              "bool f = true);\n");
  } else {
    cg_printf("#define OMIT_JUMP_TABLE_CLASS_STATIC_INVOKE_%s 1\n", clsName);
  }
  if (classScope->hasJumpTable(ClassScope::JumpTableInvoke)) {
    cg_printf("virtual Variant o_invoke(MethodIndex methodIndex, "
              "const char *s, CArrRef ps,\n");
    cg_printf("                         int64 h, bool f = true);\n");
    cg_printf("virtual Variant o_invoke_few_args(MethodIndex methodIndex, "
              "const char *s,\n");
    cg_printf("                                  int64 h, int count,\n");
    cg_printf("                                  "
              "INVOKE_FEW_ARGS_DECL_ARGS);\n");
  } else {
    cg_printf("#define OMIT_JUMP_TABLE_CLASS_INVOKE_%s 1\n", clsName);
  }

  cg_printf("\n");
  cg_printf("public:\n");
}
Exemplo n.º 26
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;
    }
  }
}
Exemplo n.º 27
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();
}