Beispiel #1
0
void CodeGenerator::printExpressionVector(ExpressionListPtr el) {
  printf("V:9:\"HH\\Vector\":%d:{", el->getCount());
  if (el->getCount() > 0) {
    el->outputCodeModel(*this);
  }
  printf("}");
}
Beispiel #2
0
ClosureExpression::ClosureExpression
(EXPRESSION_CONSTRUCTOR_PARAMETERS, FunctionStatementPtr func,
 ExpressionListPtr vars)
    : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ClosureExpression)),
      m_func(func) {

  if (vars) {
    m_vars = ExpressionListPtr
      (new ExpressionList(vars->getScope(), vars->getLocation()));
    // push the vars in reverse order, not retaining duplicates
    std::set<string> seenBefore;

    // Because PHP is insane you can have a use variable with the same
    // name as a param name.
    // In that case, params win (which is different than zend but much easier)
    ExpressionListPtr bodyParams = m_func->getParams();
    if (bodyParams) {
      int nParams = bodyParams->getCount();
      for (int i = 0; i < nParams; i++) {
        ParameterExpressionPtr par(
          static_pointer_cast<ParameterExpression>((*bodyParams)[i]));
        seenBefore.insert(par->getName());
      }
    }

    for (int i = vars->getCount() - 1; i >= 0; i--) {
      ParameterExpressionPtr param(
        dynamic_pointer_cast<ParameterExpression>((*vars)[i]));
      assert(param);
      if (seenBefore.find(param->getName().c_str()) == seenBefore.end()) {
        seenBefore.insert(param->getName().c_str());
        m_vars->insertElement(param);
      }
    }

    if (m_vars) {
      m_values = ExpressionListPtr
        (new ExpressionList(m_vars->getScope(), m_vars->getLocation()));
      for (int i = 0; i < m_vars->getCount(); i++) {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
        const string &name = param->getName();

        SimpleVariablePtr var(new SimpleVariable(param->getScope(),
                                                 param->getLocation(),
                                                 name));
        if (param->isRef()) {
          var->setContext(RefValue);
        }
        m_values->addElement(var);
      }
      assert(m_vars->getCount() == m_values->getCount());
    }
  }
}
Beispiel #3
0
ExpressionPtr Expression::unneededHelper() {
  ExpressionListPtr elist = ExpressionListPtr
    (new ExpressionList(getScope(), getRange(),
                        ExpressionList::ListKindWrapped));

  bool change = false;
  for (int i=0, n = getKidCount(); i < n; i++) {
    ExpressionPtr kid = getNthExpr(i);
    if (kid && kid->getContainedEffects()) {
      ExpressionPtr rep = kid->unneeded();
      if (rep != kid) change = true;
      if (rep->is(Expression::KindOfExpressionList)) {
        for (int j=0, m = rep->getKidCount(); j < m; j++) {
          elist->addElement(rep->getNthExpr(j));
        }
      } else {
        elist->addElement(rep);
      }
    }
  }

  if (change) {
    getScope()->addUpdates(BlockScope::UseKindCaller);
  }

  int n = elist->getCount();
  assert(n);
  if (n == 1) {
    return elist->getNthExpr(0);
  } else {
    return elist;
  }
}
void InterfaceStatement::checkArgumentsToPromote(
    FileScopeRawPtr scope, ExpressionListPtr promotedParams, int type) {
    if (!m_stmt) {
        return;
    }
    for (int i = 0; i < m_stmt->getCount(); i++) {
        MethodStatementPtr meth =
            dynamic_pointer_cast<MethodStatement>((*m_stmt)[i]);
        if (meth && meth->isNamed("__construct")) {
            ExpressionListPtr params = meth->getParams();
            if (params) {
                for (int i = 0; i < params->getCount(); i++) {
                    ParameterExpressionPtr param =
                        dynamic_pointer_cast<ParameterExpression>((*params)[i]);
                    if (param->getModifier() != 0) {
                        if (type == T_TRAIT || type == T_INTERFACE) {
                            param->parseTimeFatal(scope,
                                                  Compiler::InvalidAttribute,
                                                  "Constructor parameter promotion "
                                                  "not allowed on traits or interfaces");
                        }
                        if (promotedParams) {
                            promotedParams->addElement(param);
                        }
                    }
                }
            }
            return; // nothing else to look at
        }
    }
}
Beispiel #5
0
void Symbol::beginLocal(BlockScopeRawPtr scope) {
  m_prevCoerced = m_coerced;
  if (isClosureVar()) {
    ExpressionListPtr useVars =
      scope->getContainingFunction()->getClosureVars();
    assert(useVars);
    // linear scan for now, since most use var lists are
    // fairly short
    bool found = false;
    for (int i = 0; i < useVars->getCount(); i++) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*useVars)[i]);
      if (m_name == param->getName()) {
        // bootstrap use var with parameter type
        m_coerced = param->getType();
        found = true;
        break;
      }
    }
    if (!found) assert(false);
    assert(!isRefClosureVar() ||
           (m_coerced && m_coerced->is(Type::KindOfVariant)));
  } else {
    m_coerced.reset();
  }
}
Beispiel #6
0
void ClosureExpression::initializeFromUseList(ExpressionListPtr vars) {
  m_vars = ExpressionListPtr(
    new ExpressionList(vars->getScope(), vars->getRange()));

  // Because PHP is insane you can have a use variable with the same
  // name as a param name.
  // In that case, params win (which is different than zend but much easier)
  auto seenBefore = collectParamNames();

  for (int i = vars->getCount() - 1; i >= 0; i--) {
    auto param = dynamic_pointer_cast<ParameterExpression>((*vars)[i]);
    assert(param);
    if (param->getName() == "this") {
      // "this" is automatically included.
      // Once we get rid of all the callsites, make this an error
      continue;
    }
    if (seenBefore.find(param->getName().c_str()) == seenBefore.end()) {
      seenBefore.insert(param->getName().c_str());
      m_vars->insertElement(param);
    }
  }

  initializeValuesFromVars();
}
int BinaryOpExpression::getConcatList(ExpressionPtrVec &ev, ExpressionPtr exp,
                                      bool &hasVoid) {
  if (!exp->hasCPPTemp()) {
    if (exp->is(Expression::KindOfUnaryOpExpression)) {
      UnaryOpExpressionPtr u = static_pointer_cast<UnaryOpExpression>(exp);
      if (u->getOp() == '(') {
        return getConcatList(ev, u->getExpression(), hasVoid);
      }
    } else if (exp->is(Expression::KindOfBinaryOpExpression)) {
      BinaryOpExpressionPtr b = static_pointer_cast<BinaryOpExpression>(exp);
      if (b->getOp() == '.') {
        return getConcatList(ev, b->getExp1(), hasVoid) +
          getConcatList(ev, b->getExp2(), hasVoid);
      }
    } else if (exp->is(Expression::KindOfEncapsListExpression)) {
      EncapsListExpressionPtr e =
        static_pointer_cast<EncapsListExpression>(exp);
      if (e->getType() != '`') {
        ExpressionListPtr el = e->getExpressions();
        int num = 0;
        for (int i = 0, s = el->getCount(); i < s; i++) {
          ExpressionPtr exp = (*el)[i];
          num += getConcatList(ev, exp, hasVoid);
        }
        return num;
      }
    }
  }

  ev.push_back(exp);
  bool isVoid = !exp->getActualType();
  hasVoid |= isVoid;
  return isVoid ? 0 : 1;
}
Beispiel #8
0
void CodeGenerator::printExpressionVector(ExpressionListPtr el) {
  auto count = el == nullptr ? 0 : el->getCount();
  printf("V:9:\"HH\\Vector\":%d:{", count);
  if (count > 0) {
    el->outputCodeModel(*this);
  }
  printf("}");
}
Beispiel #9
0
void CodeGenerator::printTypeExpressionVector(ExpressionListPtr el) {
  auto count = el == nullptr ? 0 : el->getCount();
  printf("V:9:\"HH\\Vector\":%d:{", count);
  for (int i = 0; i < count; i++) {
    auto te = (*el)[i];
    printTypeExpression(te);
  }
  printf("}");
}
void BinaryOpExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
  m_exp1->outputPHP(cg, ar);

  switch (m_op) {
  case T_PLUS_EQUAL:          cg_printf(" += ");         break;
  case T_MINUS_EQUAL:         cg_printf(" -= ");         break;
  case T_MUL_EQUAL:           cg_printf(" *= ");         break;
  case T_DIV_EQUAL:           cg_printf(" /= ");         break;
  case T_CONCAT_EQUAL:        cg_printf(" .= ");         break;
  case T_MOD_EQUAL:           cg_printf(" %%= ");        break;
  case T_AND_EQUAL:           cg_printf(" &= ");         break;
  case T_OR_EQUAL:            cg_printf(" |= ");         break;
  case T_XOR_EQUAL:           cg_printf(" ^= ");         break;
  case T_SL_EQUAL:            cg_printf(" <<= ");        break;
  case T_SR_EQUAL:            cg_printf(" >>= ");        break;
  case T_BOOLEAN_OR:          cg_printf(" || ");         break;
  case T_BOOLEAN_AND:         cg_printf(" && ");         break;
  case T_LOGICAL_OR:          cg_printf(" or ");         break;
  case T_LOGICAL_AND:         cg_printf(" and ");        break;
  case T_LOGICAL_XOR:         cg_printf(" xor ");        break;
  case '|':                   cg_printf(" | ");          break;
  case '&':                   cg_printf(" & ");          break;
  case '^':                   cg_printf(" ^ ");          break;
  case '.':                   cg_printf(" . ");          break;
  case '+':                   cg_printf(" + ");          break;
  case '-':                   cg_printf(" - ");          break;
  case '*':                   cg_printf(" * ");          break;
  case '/':                   cg_printf(" / ");          break;
  case '%':                   cg_printf(" %% ");         break;
  case T_SL:                  cg_printf(" << ");         break;
  case T_SR:                  cg_printf(" >> ");         break;
  case T_IS_IDENTICAL:        cg_printf(" === ");        break;
  case T_IS_NOT_IDENTICAL:    cg_printf(" !== ");        break;
  case T_IS_EQUAL:            cg_printf(" == ");         break;
  case T_IS_NOT_EQUAL:        cg_printf(" != ");         break;
  case '<':                   cg_printf(" < ");          break;
  case T_IS_SMALLER_OR_EQUAL: cg_printf(" <= ");         break;
  case '>':                   cg_printf(" > ");          break;
  case T_IS_GREATER_OR_EQUAL: cg_printf(" >= ");         break;
  case T_INSTANCEOF:          cg_printf(" instanceof "); break;
  case T_COLLECTION: {
    ExpressionListPtr el = static_pointer_cast<ExpressionList>(m_exp2);
    if (el->getCount() == 0) {
      cg_printf(" {}");
    } else {
      cg_printf(" { ");
      el->outputPHP(cg, ar);
      cg_printf(" }");
    }
    return;
  }
  default:
    assert(false);
  }

  m_exp2->outputPHP(cg, ar);
}
Beispiel #11
0
/**
 * Rewrites any expression query clauses in this list of clauses, taking care
 * to track variables local to the query.
 */
ExpressionListPtr CaptureExtractor::rewriteExpressionList(ExpressionListPtr l) {
  int np = 0;
  int nc = l->getCount();
  auto newList =
    std::make_shared<ExpressionList>(l->getScope(), l->getRange());
  bool noRewrites = true;
  for (int i = 0; i < nc; i++) {
    auto e = (*l)[i];
    assert(e != nullptr);
    auto kind = e->getKindOf();
    switch (kind) {
      case Expression::KindOfIntoClause: {
        // The into expression is in the scope of the into clause
        SimpleQueryClausePtr qcp(static_pointer_cast<SimpleQueryClause>(e));
        m_boundVars.push_back(qcp->getIdentifier());
        np++;
        break;
      }
      case Expression::KindOfJoinClause: {
        JoinClausePtr jcp(static_pointer_cast<JoinClause>(e));
        m_boundVars.push_back(jcp->getVar());
        np++;
        break;
      }
      default:
        break;
    }
    auto ne = rewrite(e);
    if (ne != e) noRewrites = false;
    newList->addElement(ne);
    // deal with clauses that introduce names for subsequent clauses
    switch (kind) {
      case Expression::KindOfFromClause:
      case Expression::KindOfLetClause: {
        SimpleQueryClausePtr qcp(static_pointer_cast<SimpleQueryClause>(e));
        m_boundVars.push_back(qcp->getIdentifier());
        np++;
        break;
      }
      case Expression::KindOfJoinClause: {
        JoinClausePtr jcp(static_pointer_cast<JoinClause>(e));
        auto groupId = jcp->getGroup();
        if (!groupId.empty()) {
          m_boundVars.push_back(groupId);
          np++;
        }
        break;
      }
      default:
        break;
    }
  }
  while (np-- > 0) m_boundVars.pop_back();
  if (noRewrites) return l;
  return newList;
}
void UnaryOpExpression::setExistContext() {
    if (m_exp) {
        if (m_exp->is(Expression::KindOfExpressionList)) {
            ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp);
            for (int i = 0; i < exps->getCount(); i++) {
                (*exps)[i]->setContext(Expression::ExistContext);
            }
        } else {
            m_exp->setContext(Expression::ExistContext);
        }
    }
}
Beispiel #13
0
void FunctionScope::outputCPPEffectiveArguments(ExpressionListPtr params,
                                                CodeGenerator &cg,
                                                AnalysisResultPtr ar) {
  int paramCount = params ? params->getCount() : 0;
  for (int i = 0; i < paramCount; i++) {
    ExpressionPtr param = (*params)[i];
    if (param->hasEffect()) {
      param->outputCPP(cg, ar);
      cg.printf(", ");
    }
  }
}
void UnaryOpExpression::setExistContext() {
  if (m_exp) {
    if (m_exp->is(Expression::KindOfExpressionList)) {
      ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp);
      if (exps->getListKind() == ExpressionList::ListKindParam) {
        for (int i = 0; i < exps->getCount(); i++) {
          (*exps)[i]->setContext(Expression::ExistContext);
        }
        return;
      }
    }

    m_exp->setContext(Expression::ExistContext);
  }
}
int BinaryOpExpression::getConcatList(ExpressionPtrVec &ev, ExpressionPtr exp,
                                      bool &hasVoid) {
  if (!exp->hasCPPTemp()) {
    if (exp->is(Expression::KindOfUnaryOpExpression)) {
      UnaryOpExpressionPtr u = static_pointer_cast<UnaryOpExpression>(exp);
      if (u->getOp() == '(') {
        return getConcatList(ev, u->getExpression(), hasVoid);
      }
    } else if (exp->is(Expression::KindOfBinaryOpExpression)) {
      BinaryOpExpressionPtr b = static_pointer_cast<BinaryOpExpression>(exp);
      if (b->getOp() == '.') {
        if (b->getExp1()->is(Expression::KindOfSimpleVariable) &&
            b->getExp1()->isLocalExprAltered() &&
            !b->getExp1()->hasCPPTemp() &&
            b->getExp2()->hasEffect() &&
            !b->getExp2()->hasCPPTemp()) {
          /*
            In this case, the simple variable must be evaluated
            after b->getExp2(). But when we output a concat list we
            explicitly order the expressions from left to right.
          */
        } else {
          return getConcatList(ev, b->getExp1(), hasVoid) +
            getConcatList(ev, b->getExp2(), hasVoid);
        }
      }
    } else if (exp->is(Expression::KindOfEncapsListExpression)) {
      EncapsListExpressionPtr e =
        static_pointer_cast<EncapsListExpression>(exp);
      if (e->getType() != '`') {
        ExpressionListPtr el = e->getExpressions();
        int num = 0;
        for (int i = 0, s = el->getCount(); i < s; i++) {
          ExpressionPtr exp = (*el)[i];
          num += getConcatList(ev, exp, hasVoid);
        }
        return num;
      }
    }
  } else if (!exp->getActualType()) {
    return 0;
  }

  ev.push_back(exp);
  bool isVoid = !exp->getActualType();
  hasVoid |= isVoid;
  return isVoid ? 0 : 1;
}
bool UnaryOpExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
                                     int state) {

    if (m_op == T_ISSET && m_exp && m_exp->is(Expression::KindOfExpressionList)) {
        ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp);
        int count = exps->getCount();
        if (count > 1) {
            bool fix_e1 = (*exps)[0]->preOutputCPP(cg, ar, 0);
            bool inExpression = ar->inExpression();
            ar->setInExpression(false);
            bool fix_en = false;
            for (int i = 1; i < count; i++) {
                if ((*exps)[i]->preOutputCPP(cg, ar, 0)) {
                    fix_en = true;
                    break;
                }
            }
            ar->setInExpression(inExpression);
            if (inExpression && fix_en) {
                ar->wrapExpressionBegin(cg);
                std::string tmp = genCPPTemp(cg, ar);
                cg.printf("bool %s = (", tmp.c_str());
                (*exps)[0]->outputCPPExistTest(cg, ar, m_op);
                cg.printf(");\n");
                for (int i = 1; i < count; i++) {
                    cg.indentBegin("if (%s) {\n", tmp.c_str());
                    ExpressionPtr e = (*exps)[i];
                    e->preOutputCPP(cg, ar, 0);
                    cg.printf("%s = (", tmp.c_str());
                    e->outputCPPExistTest(cg, ar, m_op);
                    cg.printf(");\n");
                }
                for (int i = 1; i < count; i++) {
                    cg.indentEnd("}\n");
                }
                m_cppTemp = tmp;
            } else if (state & FixOrder) {
                preOutputStash(cg, ar, state);
                fix_e1 = true;
            }
            return fix_e1 || fix_en;
        }
    }

    return Expression::preOutputCPP(cg, ar, state);
}
static bool AssignmentCouldSet(ExpressionListPtr vars, ExpressionPtr var) {
  for (int i = 0; i < vars->getCount(); i++) {
    ExpressionPtr v = (*vars)[i];
    if (!v) continue;
    if (v->is(Expression::KindOfSimpleVariable) &&
        v->canonCompare(var)) {
      return true;
    }
    if (v->is(Expression::KindOfDynamicVariable)) return true;
    if (v->is(Expression::KindOfListAssignment) &&
        AssignmentCouldSet(static_pointer_cast<ListAssignment>(v)->
                           getVariables(), var)) {
      return true;
    }
  }
  return false;
}
ClosureExpression::ClosureExpression
(EXPRESSION_CONSTRUCTOR_PARAMETERS, FunctionStatementPtr func,
 ExpressionListPtr vars)
    : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ClosureExpression)),
      m_func(func) {

  if (vars) {
    m_vars = ExpressionListPtr
      (new ExpressionList(vars->getScope(), vars->getLocation()));
    // push the vars in reverse order, not retaining duplicates
    std::set<string> seenBefore;
    for (int i = vars->getCount() - 1; i >= 0; i--) {
      ParameterExpressionPtr param(
        dynamic_pointer_cast<ParameterExpression>((*vars)[i]));
      assert(param);
      if (param->getName() == "this") {
        // "this" is automatically included.
        // Once we get rid of all the callsites, make this an error
        continue;
      }
      if (seenBefore.find(param->getName().c_str()) == seenBefore.end()) {
        seenBefore.insert(param->getName().c_str());
        m_vars->insertElement(param);
      }
    }

    if (m_vars) {
      m_values = ExpressionListPtr
        (new ExpressionList(m_vars->getScope(), m_vars->getLocation()));
      for (int i = 0; i < m_vars->getCount(); i++) {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
        const string &name = param->getName();

        SimpleVariablePtr var(new SimpleVariable(param->getScope(),
                                                 param->getLocation(),
                                                 name));
        if (param->isRef()) {
          var->setContext(RefValue);
        }
        m_values->addElement(var);
      }
      assert(m_vars->getCount() == m_values->getCount());
    }
  }
}
Beispiel #19
0
bool Option::Load(map<string, int> &option, ExpressionPtr value) {
  ExpressionListPtr elements;
  if (!GetArrayElements(value, elements)) return false;

  for (int i = 0; i < elements->getCount(); i++) {
    ExpressionPtr e = (*elements)[i];
    ArrayPairExpressionPtr pair = dynamic_pointer_cast<ArrayPairExpression>(e);

    bool negative = false;
    ScalarExpressionPtr n, v;
    if (pair) n = dynamic_pointer_cast<ScalarExpression>(pair->getName());
    if (pair) {
      if (pair->getValue()->is(Expression::KindOfUnaryOpExpression)) {
        UnaryOpExpressionPtr una =
          dynamic_pointer_cast<UnaryOpExpression>(pair->getValue());
        if (una->getOp() != '+' && una->getOp() != '-') {
          Logger::Error("Line %d: invalid integer: %s",
                        una->getLocation()->line1, una->getText().c_str());
          return false;
        }

        v = dynamic_pointer_cast<ScalarExpression>(una->getExpression());
        if (una->getOp() == '-') {
          negative = true;
        }
      } else {
        v = dynamic_pointer_cast<ScalarExpression>(pair->getValue());
      }
    }

    if (!pair || !n || !v || !n->isLiteralString() || !v->isLiteralInteger()) {
      Logger::Error("Line %d: invalid element: %s", e->getLocation()->line1,
                    e->getText().c_str());
      return false;
    }

    if (negative) {
      option[n->getLiteralString()] = - v->getLiteralInteger();
    } else {
      option[n->getLiteralString()] = v->getLiteralInteger();
    }
  }

  return true;
}
ClosureExpression::ClosureExpression
(EXPRESSION_CONSTRUCTOR_PARAMETERS, FunctionStatementPtr func,
 ExpressionListPtr vars)
    : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES),
      m_func(func) {

  if (vars) {
    m_vars = ExpressionListPtr
      (new ExpressionList(vars->getScope(), vars->getLocation(),
                          KindOfExpressionList));
    // push the vars in reverse order, not retaining duplicates
    set<string> seenBefore;
    for (int i = vars->getCount() - 1; i >= 0; i--) {
      ParameterExpressionPtr param(
        dynamic_pointer_cast<ParameterExpression>((*vars)[i]));
      ASSERT(param);
      if (seenBefore.find(param->getName().c_str()) == seenBefore.end()) {
        seenBefore.insert(param->getName().c_str());
        m_vars->insertElement(param);
      }
    }

    if (m_vars) {
      m_values = ExpressionListPtr
        (new ExpressionList(m_vars->getScope(), m_vars->getLocation(),
                            KindOfExpressionList));
      for (int i = 0; i < m_vars->getCount(); i++) {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
        string name = param->getName();

        SimpleVariablePtr var(new SimpleVariable(param->getScope(),
                                                 param->getLocation(),
                                                 KindOfSimpleVariable,
                                                 name));
        if (param->isRef()) {
          var->setContext(RefValue);
        }
        m_values->addElement(var);
      }
    }
  }
}
Beispiel #21
0
bool Option::Load(vector<string> &option, ExpressionPtr value) {
  ExpressionListPtr elements;
  if (!GetArrayElements(value, elements)) return false;

  for (int i = 0; i < elements->getCount(); i++) {
    ExpressionPtr e = (*elements)[i];
    ArrayPairExpressionPtr pair = dynamic_pointer_cast<ArrayPairExpression>(e);

    ScalarExpressionPtr v;
    if (pair) v = dynamic_pointer_cast<ScalarExpression>(pair->getValue());

    if (!pair || !v || !v->isLiteralString()) {
      Logger::Error("Line %d: invalid element: %s", e->getLocation()->line1,
                    e->getText().c_str());
      return false;
    }
    option.push_back(v->getLiteralString());
  }

  return true;
}
TypePtr UnaryOpExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
                                      bool coerce) {
  TypePtr et; // expected m_exp's type
  TypePtr rt; // return type

  switch (m_op) {
  case '!':             et = rt = Type::Boolean;                     break;
  case '+':
  case '-':             et = Type::Numeric; rt = Type::Numeric;      break;
  case T_INC:
  case T_DEC:
  case '~':             et = rt = Type::Primitive;                   break;
  case T_CLONE:         et = Type::Some;      rt = Type::Object;     break;
  case '@':             et = type;            rt = Type::Variant;    break;
  case T_INT_CAST:      et = rt = Type::Int64;                       break;
  case T_DOUBLE_CAST:   et = rt = Type::Double;                      break;
  case T_STRING_CAST:   et = rt = Type::String;                      break;
  case T_ARRAY:         et = Type::Some;      rt = Type::Array;      break;
  case T_ARRAY_CAST:    et = rt = Type::Array;                       break;
  case T_OBJECT_CAST:   et = rt = Type::Object;                      break;
  case T_BOOL_CAST:     et = rt = Type::Boolean;                     break;
  case T_UNSET_CAST:    et = Type::Some;      rt = Type::Variant;    break;
  case T_UNSET:         et = Type::Null;      rt = Type::Variant;    break;
  case T_EXIT:          et = Type::Primitive; rt = Type::Variant;    break;
  case T_PRINT:         et = Type::String;    rt = Type::Int64;      break;
  case T_ISSET:         et = Type::Variant;   rt = Type::Boolean;
    setExistContext();
    break;
  case T_EMPTY:         et = Type::Some;      rt = Type::Boolean;
    setExistContext();
    break;
  case T_INCLUDE:
  case T_INCLUDE_ONCE:
  case T_REQUIRE:
  case T_REQUIRE_ONCE:  et = Type::String;    rt = Type::Variant;    break;
  case T_EVAL:
    et = Type::String;
    rt = Type::Any;
    getScope()->getVariables()->forceVariants(ar, VariableTable::AnyVars);
    break;
  case T_DIR:
  case T_FILE:          et = rt = Type::String;                      break;
  default:
    assert(false);
  }

  if (m_exp) {
    TypePtr expType = m_exp->inferAndCheck(ar, et, false);
    if (Type::SameType(expType, Type::String) &&
        (m_op == T_INC || m_op == T_DEC)) {
      rt = expType = m_exp->inferAndCheck(ar, Type::Variant, true);
    }

    switch (m_op) {
    case '+':
    case '-':
      if (Type::SameType(expType, Type::Int64) ||
          Type::SameType(expType, Type::Double)) {
        rt = expType;
      }
      break;
    case T_INC:
    case T_DEC:
    case '~':
      if (Type::SameType(expType, Type::Int64) ||
          Type::SameType(expType, Type::Double) ||
          Type::SameType(expType, Type::String)) {
        rt = expType;
      }
      break;
    case T_ISSET:
    case T_EMPTY:
      if (m_exp->is(Expression::KindOfExpressionList)) {
        ExpressionListPtr exps =
          dynamic_pointer_cast<ExpressionList>(m_exp);
        if (exps->getListKind() == ExpressionList::ListKindParam) {
          for (int i = 0; i < exps->getCount(); i++) {
            SetExpTypeForExistsContext(ar, (*exps)[i], m_op == T_EMPTY);
          }
        }
      } else {
        SetExpTypeForExistsContext(ar, m_exp, m_op == T_EMPTY);
      }
      break;
    default:
      break;
    }
  }

  return rt;
}
void UnaryOpExpression::outputCPPImpl(CodeGenerator &cg,
                                      AnalysisResultPtr ar) {
  if ((m_op == T_INC || m_op == T_DEC) && outputCPPImplOpEqual(cg, ar)) {
    return;
  }
  if (m_op == T_ARRAY &&
      (getContext() & (RefValue|LValue)) == 0 &&
      !ar->getInsideScalarArray()) {
    int id = -1;
    int hash = -1;
    int index = -1;
    string text;
    if (m_exp) {
      ExpressionListPtr pairs = dynamic_pointer_cast<ExpressionList>(m_exp);
      Variant v;
      if (pairs && pairs->isScalarArrayPairs() && pairs->getScalarValue(v)) {
        id = ar->registerScalarArray(getFileScope(), m_exp, hash, index, text);
      }
    } else {
      id = ar->registerScalarArray(getFileScope(), m_exp,
                                   hash, index, text); // empty array
    }
    if (id != -1) {
      if (Option::UseNamedScalarArray &&
          cg.getContext() == CodeGenerator::CppParameterDefaultValueDecl) {
        getFileScope()->addUsedDefaultValueScalarArray(text);
      }
      ar->outputCPPScalarArrayId(cg, id, hash, index);
      return;
    }
  }

  if ((m_op == T_ISSET || m_op == T_EMPTY || m_op == T_UNSET) && m_exp) {
    if (m_exp->is(Expression::KindOfExpressionList)) {
      ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp);
      if (exps->getListKind() == ExpressionList::ListKindParam) {
        int count = exps->getCount();
        if (count > 1) {
          cg_printf("(");
        }
        for (int i = 0; i < count; i++) {
          if (m_op == T_UNSET) {
            if (i > 0) cg_printf(", ");
            (*exps)[i]->outputCPPUnset(cg, ar);
          } else {
            if (i > 0) cg_printf(" && ");
            (*exps)[i]->outputCPPExistTest(cg, ar, m_op);
          }
        }
        if (exps->getCount() > 1) {
          cg_printf(")");
        }
        return;
      }
    }
    if (m_op == T_UNSET) {
      m_exp->outputCPPUnset(cg, ar);
    } else {
      m_exp->outputCPPExistTest(cg, ar, m_op);
    }
    return;
  }

  if (m_front) {
    switch (m_op) {
    case T_CLONE:         cg_printf("f_clone(");   break;
    case T_INC:           cg_printf("++");         break;
    case T_DEC:           cg_printf("--");         break;
    case '+':             cg_printf("+");          break;
    case '-':             cg_printf("negate(");    break;
    case '!':             cg_printf("!(");         break;
    case '~':             cg_printf("~");          break;
    case '(':             cg_printf("(");          break;
    case T_INT_CAST:      cg_printf("(");          break;
    case T_DOUBLE_CAST:   cg_printf("(");          break;
    case T_STRING_CAST:   cg_printf("(");          break;
    case T_ARRAY_CAST:    cg_printf("(");          break;
    case T_OBJECT_CAST:   cg_printf("(");          break;
    case T_BOOL_CAST:     cg_printf("(");          break;
    case T_UNSET_CAST:
      if (m_exp->hasCPPTemp()) {
        cg_printf("(id(");
      } else {
        cg_printf("(");
      }
      break;
    case T_EXIT:          cg_printf("f_exit(");    break;
    case T_ARRAY:
      cg_printf("Array(");
      break;
    case T_PRINT:         cg_printf("print(");     break;
    case T_EVAL:
      if (Option::EnableEval > Option::NoEval) {
        bool instance;
        if (getClassScope()) {
          FunctionScopePtr fs = getFunctionScope();
          instance = fs && !fs->isStatic();
        } else {
          instance = false;
        }
        cg_printf("eval(%s, Object(%s), ",
                  getScope()->inPseudoMain() ?
                  "get_variable_table()" : "variables",
                  instance ? "this" : "");
      } else {
        cg_printf("f_eval(");
      }
      break;
    case '@':
      if (m_silencer >= 0) {
        cg_printf("(%s%d.enable(),%s%d.disable(",
                  Option::SilencerPrefix, m_silencer,
                  Option::SilencerPrefix, m_silencer);
      }
      break;
    case T_FILE:
      cg_printf("get_source_filename(\"%s\")", getLocation()->file);
      break;
      break;
    default:
      ASSERT(false);
    }
  }


  if (m_exp) {
    switch (m_op) {
    case '+':
    case '-':
      if (m_exp->getActualType() &&
          (m_exp->getActualType()->is(Type::KindOfString) ||
           m_exp->getActualType()->is(Type::KindOfArray))) {
        cg_printf("(Variant)(");
        m_exp->outputCPP(cg, ar);
        cg_printf(")");
      } else {
        m_exp->outputCPP(cg, ar);
      }
      break;
    case '@':
      if (m_silencer < 0 && isUnused()) {
        m_exp->outputCPPUnneeded(cg, ar);
      } else if (!m_exp->hasCPPTemp() && !m_exp->getActualType()) {
        // Void needs to return something to silenceDec
        cg_printf("(");
        m_exp->outputCPP(cg, ar);
        cg_printf(",null)");
      } else {
        m_exp->outputCPP(cg, ar);
      }
      break;
    default:
      m_exp->outputCPP(cg, ar);
      break;
    }
  }

  if (m_front) {
    switch (m_op) {
    case T_ARRAY:
      {
        ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp);
        if (!exps) {
          cg_printf("ArrayData::Create()");
        }
        cg_printf(")");
      }
      break;
    case T_UNSET_CAST:
      if (m_exp->hasCPPTemp()) {
        cg_printf("),null");
      } else {
        cg_printf(",null");
      }
    case T_CLONE:
    case '!':
    case '(':
    case '-':
    case T_INT_CAST:
    case T_DOUBLE_CAST:
    case T_STRING_CAST:
    case T_ARRAY_CAST:
    case T_OBJECT_CAST:
    case T_BOOL_CAST:
    case T_EXIT:
    case T_PRINT:
    case T_EVAL:
    case T_INCLUDE:
    case T_INCLUDE_ONCE:
    case T_REQUIRE:
    case T_REQUIRE_ONCE:
      cg_printf(")");
      break;
    case '@':
      if (m_silencer >= 0) {
        cg_printf("))");
      }
      break;
    default:
      break;
    }
  } else {
    switch (m_op) {
    case T_INC:           cg_printf("++"); break;
    case T_DEC:           cg_printf("--"); break;
    default:
      ASSERT(false);
    }
  }
}
void UnaryOpExpression::outputCPPImpl(CodeGenerator &cg,
                                      AnalysisResultPtr ar) {
    if (m_arrayId != -1) {
        if (cg.getOutput() == CodeGenerator::SystemCPP) {
            cg.printf("SystemScalarArrays::%s[%d]",
                      Option::SystemScalarArrayName, m_arrayId);
        } else {
            cg.printf("ScalarArrays::%s[%d]",
                      Option::ScalarArrayName, m_arrayId);
        }
        return;
    }

    if ((m_op == T_ISSET || m_op == T_EMPTY) && m_exp) {
        if (m_exp->is(Expression::KindOfExpressionList)) {
            ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp);
            if (exps->getCount() > 1) {
                cg.printf("(");
            }
            for (int i = 0; i < exps->getCount(); i++) {
                if (i > 0) cg.printf(" && ");
                (*exps)[i]->outputCPPExistTest(cg, ar, m_op);
            }
            if (exps->getCount() > 1) {
                cg.printf(")");
            }
        } else {
            m_exp->outputCPPExistTest(cg, ar, m_op);
        }
        return;
    }

    if (m_front) {
        switch (m_op) {
        case T_CLONE:
            cg.printf("f_clone(");
            break;
        case T_INC:
            cg.printf("++");
            break;
        case T_DEC:
            cg.printf("--");
            break;
        case '+':
            cg.printf("+");
            break;
        case '-':
            cg.printf("negate(");
            break;
        case '!':
            cg.printf("!(");
            break;
        case '~':
            cg.printf("~");
            break;
        case '(':
            cg.printf("(");
            break;
        case T_INT_CAST:
            cg.printf("(");
            break;
        case T_DOUBLE_CAST:
            cg.printf("(");
            break;
        case T_STRING_CAST:
            cg.printf("(");
            break;
        case T_ARRAY_CAST:
            cg.printf("(");
            break;
        case T_OBJECT_CAST:
            cg.printf("(");
            break;
        case T_BOOL_CAST:
            cg.printf("(");
            break;
        case T_UNSET_CAST:
            cg.printf("unset(");
            break;
        case T_EXIT:
            cg.printf("f_exit(");
            break;
        case T_ARRAY:
            if (ar->getInsideScalarArray()) {
                cg.printf("StaticArray(");
            } else {
                cg.printf("Array(");
            }
            break;
        case T_PRINT:
            cg.printf("print(");
            break;
        case T_EVAL:
            if (Option::EnableEval > Option::NoEval) {
                cg.printf("eval(%s, Object(%s), ",
                          ar->getScope()->inPseudoMain() ?
                          "get_variable_table()" : "variables",
                          ar->getClassScope() ? "this" : "");
            } else {
                cg.printf("f_eval(");
            }
            break;
        case '@':
            cg.printf("(%s%d.enable(),%s%d.disable(",
                      Option::SilencerPrefix, m_silencer,
                      Option::SilencerPrefix, m_silencer);
            break;
        case T_FILE:
            cg.printf("get_source_filename(\"%s\")", getLocation()->file);
            break;
            break;
        default:
            ASSERT(false);
        }
    }


    if (m_exp) {
        switch (m_op) {
        case '+':
        case '-':
            if (m_exp->getActualType() &&
                    (m_exp->getActualType()->is(Type::KindOfString) ||
                     m_exp->getActualType()->is(Type::KindOfArray))) {
                cg.printf("(Variant)(");
                m_exp->outputCPP(cg, ar);
                cg.printf(")");
            } else {
                m_exp->outputCPP(cg, ar);
            }
            break;
        case '@':
            // Void needs to return something to silenceDec
            if (!m_exp->getActualType()) {
                cg.printf("(");
                m_exp->outputCPP(cg, ar);
                cg.printf(",null)");
            } else {
                m_exp->outputCPP(cg, ar);
            }
            break;
        default:
            m_exp->outputCPP(cg, ar);
            break;
        }
    }

    if (m_front) {
        switch (m_op) {
        case T_ARRAY:
        {
            ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp);
            if (!exps) {
                cg.printf("ArrayData::Create()");
            }
            cg.printf(")");
        }
        break;
        case T_CLONE:
        case '!':
        case '(':
        case '-':
        case T_INT_CAST:
        case T_DOUBLE_CAST:
        case T_STRING_CAST:
        case T_ARRAY_CAST:
        case T_OBJECT_CAST:
        case T_BOOL_CAST:
        case T_UNSET_CAST:
        case T_EXIT:
        case T_PRINT:
        case T_EVAL:
        case T_INCLUDE:
        case T_INCLUDE_ONCE:
        case T_REQUIRE:
        case T_REQUIRE_ONCE:
            cg.printf(")");
            break;
        case '@':
            cg.printf("))");
            break;
        default:
            break;
        }
    } else {
        switch (m_op) {
        case T_INC:
            cg.printf("++");
            break;
        case T_DEC:
            cg.printf("--");
            break;
        default:
            ASSERT(false);
        }
    }
}
bool UnaryOpExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
                                     int state) {

  if (m_op == T_ISSET && m_exp && m_exp->is(Expression::KindOfExpressionList)) {
    ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp);
    int count = exps->getCount();
    if (count > 1) {
      bool fix_e1 = (*exps)[0]->preOutputCPP(cg, ar, 0);
      bool inExpression = ar->inExpression();
      ar->setInExpression(false);
      bool fix_en = false;
      for (int i = 1; i < count; i++) {
        if ((*exps)[i]->preOutputCPP(cg, ar, 0)) {
          fix_en = true;
          break;
        }
      }
      ar->setInExpression(inExpression);
      if (inExpression && fix_en) {
        ar->wrapExpressionBegin(cg);
        std::string tmp = genCPPTemp(cg, ar);
        cg_printf("bool %s = (", tmp.c_str());
        (*exps)[0]->outputCPPExistTest(cg, ar, m_op);
        cg_printf(");\n");
        for (int i = 1; i < count; i++) {
          cg_indentBegin("if (%s) {\n", tmp.c_str());
          ExpressionPtr e = (*exps)[i];
          e->preOutputCPP(cg, ar, 0);
          cg_printf("%s = (", tmp.c_str());
          e->outputCPPExistTest(cg, ar, m_op);
          cg_printf(");\n");
        }
        for (int i = 1; i < count; i++) {
          cg_indentEnd("}\n");
        }
        m_cppTemp = tmp;
      } else if (state & FixOrder) {
        preOutputStash(cg, ar, state);
        fix_e1 = true;
      }
      return fix_e1 || fix_en;
    }
  }

  if (m_op == '@') {
    if (isUnused()) m_exp->setUnused(true);
    bool inExpression = ar->inExpression();
    bool doit = state & FixOrder;
    if (!doit) {
      ar->setInExpression(false);
      if (m_exp->preOutputCPP(cg, ar, state)) {
        doit = true;
      }
      ar->setInExpression(inExpression);
    }
    if (doit && inExpression) {
      cg_printf("%s%d.enable();\n", Option::SilencerPrefix, m_silencer);
      m_exp->preOutputCPP(cg, ar, 0);
      int s = m_silencer;
      m_silencer = -1;
      this->preOutputStash(cg, ar, state | FixOrder);
      m_silencer = s;
      cg_printf("%s%d.disable();\n", Option::SilencerPrefix, m_silencer);
    }
    return doit;
  } else if (m_op == T_PRINT && m_exp && !m_exp->hasEffect()) {
    ExpressionPtrVec ev;
    bool hasVoid = false;
    if (BinaryOpExpression::getConcatList(ev, m_exp, hasVoid) > 1 ||
        hasVoid ) {

      if (!ar->inExpression()) return true;
      ar->wrapExpressionBegin(cg);
      for (int i = 0, s = ev.size(); i < s; i++) {
        ExpressionPtr e = ev[i];
        e->preOutputCPP(cg, ar, 0);
        cg_printf("print(");
        e->outputCPP(cg, ar);
        cg_printf(");\n");
      }
      m_cppTemp = "1";
      return true;
    }
  }

  return Expression::preOutputCPP(cg, ar, state);
}
int FunctionScope::inferParamTypes(AnalysisResultPtr ar, ConstructPtr exp,
                                   ExpressionListPtr params, bool &valid) {
  if (!params) {
    if (m_minParam > 0) {
      if (exp->getScope()->isFirstPass()) {
        Compiler::Error(Compiler::TooFewArgument, exp, m_stmt);
      }
      valid = false;
      if (!Option::AllDynamic) setDynamic();
    }
    return 0;
  }

  int ret = 0;
  if (params->getCount() < m_minParam) {
    if (exp->getScope()->isFirstPass()) {
      Compiler::Error(Compiler::TooFewArgument, exp, m_stmt);
    }
    valid = false;
    if (!Option::AllDynamic) setDynamic();
  }
  if (params->getCount() > m_maxParam) {
    if (isVariableArgument()) {
      ret = params->getCount() - m_maxParam;
    } else {
      if (exp->getScope()->isFirstPass()) {
        Compiler::Error(Compiler::TooManyArgument, exp, m_stmt);
      }
      valid = false;
      if (!Option::AllDynamic) setDynamic();
    }
  }

  bool canSetParamType = isUserFunction() && !m_overriding && !m_perfectVirtual;
  for (int i = 0; i < params->getCount(); i++) {
    ExpressionPtr param = (*params)[i];
    if (i < m_maxParam && param->hasContext(Expression::RefParameter)) {
      /**
       * This should be very un-likely, since call time pass by ref is a
       * deprecated, not very widely used (at least in FB codebase) feature.
       */
      TRY_LOCK_THIS();
      Symbol *sym = getVariables()->addSymbol(m_paramNames[i]);
      sym->setLvalParam();
      sym->setCallTimeRef();
    }
    if (valid && param->hasContext(Expression::InvokeArgument)) {
      param->clearContext(Expression::InvokeArgument);
      param->clearContext(Expression::RefValue);
      param->clearContext(Expression::NoRefWrapper);
    }
    bool isRefVararg = (i >= m_maxParam && isReferenceVariableArgument());
    if ((i < m_maxParam && isRefParam(i)) || isRefVararg) {
      param->setContext(Expression::LValue);
      param->setContext(Expression::RefValue);
      param->inferAndCheck(ar, Type::Variant, true);
    } else if (!(param->getContext() & Expression::RefParameter)) {
      param->clearContext(Expression::LValue);
      param->clearContext(Expression::RefValue);
      param->clearContext(Expression::InvokeArgument);
      param->clearContext(Expression::NoRefWrapper);
    }
    TypePtr expType;
    /**
     * Duplicate the logic of getParamType(i), w/o the mutation
     */
    TypePtr paramType(i < m_maxParam && !isZendParamMode() ?
                      m_paramTypes[i] : TypePtr());
    if (!paramType) paramType = Type::Some;
    if (valid && !canSetParamType && i < m_maxParam &&
        (!Option::HardTypeHints || !m_paramTypeSpecs[i])) {
      /**
       * What is this magic, you might ask?
       *
       * Here, we take advantage of implicit conversion from every type to
       * Variant. Essentially, we don't really care what type comes out of this
       * expression since it'll just get converted anyways. Doing it this way
       * allows us to generate less temporaries along the way.
       */
      TypePtr optParamType(paramType->is(Type::KindOfVariant) ?
                           Type::Some : paramType);
      expType = param->inferAndCheck(ar, optParamType, false);
    } else {
      expType = param->inferAndCheck(ar, Type::Some, false);
    }
    if (i < m_maxParam) {
      if (!Option::HardTypeHints || !m_paramTypeSpecs[i]) {
        if (canSetParamType) {
          if (!Type::SameType(paramType, expType) &&
              !paramType->is(Type::KindOfVariant)) {
            TRY_LOCK_THIS();
            paramType = setParamType(ar, i, expType);
          } else {
            // do nothing - how is this safe?  well, if we ever observe
            // paramType == expType, then this means at some point in the past,
            // somebody called setParamType() with expType.  thus, by calling
            // setParamType() again with expType, we contribute no "new"
            // information. this argument also still applies in the face of
            // concurrency
          }
        }
        // See note above. If we have an implemented type, however, we
        // should set the paramType to the implemented type to avoid an
        // un-necessary cast
        if (paramType->is(Type::KindOfVariant)) {
          TypePtr it(param->getImplementedType());
          paramType = it ? it : expType;
        }
        if (valid) {
          if (!Type::IsLegalCast(ar, expType, paramType) &&
              paramType->isNonConvertibleType()) {
            param->inferAndCheck(ar, paramType, true);
          }
          param->setExpectedType(paramType);
        }
      }
    }
    // we do a best-effort check for bad pass-by-reference and do not report
    // error for some vararg case (e.g., array_multisort can have either ref
    // or value for the same vararg).
    if (!isRefVararg || !isMixedVariableArgument()) {
      Expression::CheckPassByReference(ar, param);
    }
  }
  return ret;
}
Beispiel #27
0
void FunctionScope::outputCPPClassMap(CodeGenerator &cg, AnalysisResultPtr ar) {
  int attribute = ClassInfo::IsNothing;
  if (!isUserFunction()) attribute |= ClassInfo::IsSystem;
  if (isRedeclaring()) attribute |= ClassInfo::IsRedeclared;
  if (isVolatile()) attribute |= ClassInfo::IsVolatile;
  if (isRefReturn()) attribute |= ClassInfo::IsReference;

  if (isProtected()) {
    attribute |= ClassInfo::IsProtected;
  } else if (isPrivate()) {
    attribute |= ClassInfo::IsPrivate;
  } else {
    attribute |= ClassInfo::IsPublic;
  }
  if (isAbstract()) attribute |= ClassInfo::IsAbstract;
  if (isStatic() && !isStaticMethodAutoFixed()) {
    attribute |= ClassInfo::IsStatic;
  }
  if (isFinal()) attribute |= ClassInfo::IsFinal;
  if (!m_docComment.empty()) attribute |= ClassInfo::HasDocComment;

  // Use the original cased name, for reflection to work correctly.
  cg.printf("(const char *)0x%04X, \"%s\", NULL, NULL,\n", attribute,
            getOriginalName().c_str());

  if (!m_docComment.empty()) {
    char *dc = string_cplus_escape(m_docComment.c_str());
    cg.printf("\"%s\",\n", dc);
    free(dc);
  }

  Variant defArg;
  for (int i = 0; i < m_maxParam; i++) {
    int attr = ClassInfo::IsNothing;
    if (i >= m_minParam) attr |= ClassInfo::IsOptional;
    if (isRefParam(i)) attr |= ClassInfo::IsReference;

    cg.printf("(const char *)0x%04X, \"%s\", \"%s\", ",
              attr, m_paramNames[i].c_str(),
              Util::toLower(m_paramTypes[i]->getPHPName()).c_str());

    if (i >= m_minParam) {
      MethodStatementPtr m =
        dynamic_pointer_cast<MethodStatement>(getStmt());
      if (m) {
        ExpressionListPtr params = m->getParams();
        assert(i < params->getCount());
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*params)[i]);
        assert(param);
        ExpressionPtr def = param->defaultValue();
        if (!def->isScalar() || !def->getScalarValue(defArg)) {
          defArg = "1";
        }
      } else {
        defArg = "1";
      }
      char *s = string_cplus_escape(f_serialize(defArg).data());
      cg.printf("\"%s\",\n", s);
      free(s);
    } else {
      cg.printf("\"\",\n");
    }
  }
  cg.printf("NULL,\n");

  m_variables->outputCPPStaticVariables(cg, ar);
}
Beispiel #28
0
int FunctionScope::inferParamTypes(AnalysisResultPtr ar, ConstructPtr exp,
                                   ExpressionListPtr params, bool &valid) {
  if (!params) {
    if (m_minParam > 0) {
      if (ar->isFirstPass()) {
        ar->getCodeError()->record(CodeError::TooFewArgument, exp, m_stmt);
      }
      valid = false;
      setDynamic();
    }
    return 0;
  }

  int ret = 0;
  if (params->getCount() < m_minParam) {
    if (ar->isFirstPass()) {
      ar->getCodeError()->record(CodeError::TooFewArgument, exp, m_stmt);
    }
    valid = false;
    setDynamic();
  }
  if (params->getCount() > m_maxParam) {
    if (isVariableArgument()) {
      ret = params->getCount() - m_maxParam;
    } else {
      if (ar->isFirstPass()) {
        ar->getCodeError()->record(CodeError::TooManyArgument, exp, m_stmt);
      }
      valid = false;
      setDynamic();
    }
  }

  bool canSetParamType = isUserFunction() && !m_overriding;
  for (int i = 0; i < params->getCount(); i++) {
    ExpressionPtr param = (*params)[i];
    if (valid && param->hasContext(Expression::InvokeArgument)) {
      param->clearContext(Expression::InvokeArgument);
      param->clearContext(Expression::RefValue);
      param->clearContext(Expression::NoRefWrapper);
    }
    TypePtr expType;
    if (!canSetParamType && i < m_maxParam) {
      expType = param->inferAndCheck(ar, getParamType(i), false);
    } else {
      expType = param->inferAndCheck(ar, NEW_TYPE(Some), false);
    }
    bool isRefVararg = (i >= m_maxParam && isReferenceVariableArgument());
    if ((i < m_maxParam && isRefParam(i)) || isRefVararg) {
      param->setContext(Expression::LValue);
      param->setContext(Expression::RefValue);
      param->inferAndCheck(ar, Type::Variant, true);
    } else if (!(param->getContext() & Expression::RefParameter)) {
      param->clearContext(Expression::LValue);
      param->clearContext(Expression::RefValue);
      param->clearContext(Expression::InvokeArgument);
      param->clearContext(Expression::NoRefWrapper);
    }
    if (i < m_maxParam) {
      if (m_paramTypeSpecs[i] && ar->isFirstPass()) {
        if (!Type::Inferred(ar, expType, m_paramTypeSpecs[i])) {
          const char *file = m_stmt->getLocation()->file;
          Logger::Error("%s: parameter %d of %s requires %s, called with %s",
                        file, i, m_name.c_str(),
                        m_paramTypeSpecs[i]->toString().c_str(),
                        expType->toString().c_str());
          ar->getCodeError()->record(CodeError::BadArgumentType, m_stmt);
        }
      }
      TypePtr paramType = getParamType(i);
      if (canSetParamType) {
        paramType = setParamType(ar, i, expType);
      }
      if (!Type::IsLegalCast(ar, expType, paramType) &&
          paramType->isNonConvertibleType()) {
        param->inferAndCheck(ar, paramType, true);
      }
      param->setExpectedType(paramType);
    }
    // we do a best-effort check for bad pass-by-reference and do not report
    // error for some vararg case (e.g., array_multisort can have either ref
    // or value for the same vararg).
    if (!isRefVararg || !isMixedVariableArgument()) {
      Expression::checkPassByReference(ar, param);
    }
  }
  return ret;
}
Beispiel #29
0
void FunctionScope::outputCPPClassMap(CodeGenerator &cg, AnalysisResultPtr ar) {
  int attribute = ClassInfo::IsNothing;
  if (!isUserFunction()) attribute |= ClassInfo::IsSystem;
  if (isRedeclaring()) attribute |= ClassInfo::IsRedeclared;
  if (isVolatile()) attribute |= ClassInfo::IsVolatile;
  if (isRefReturn()) attribute |= ClassInfo::IsReference;

  if (isProtected()) {
    attribute |= ClassInfo::IsProtected;
  } else if (isPrivate()) {
    attribute |= ClassInfo::IsPrivate;
  } else {
    attribute |= ClassInfo::IsPublic;
  }
  if (isAbstract()) attribute |= ClassInfo::IsAbstract;
  if (isStatic()) {
    attribute |= ClassInfo::IsStatic;
  }
  if (isFinal()) attribute |= ClassInfo::IsFinal;

  if (isVariableArgument()) {
    attribute |= ClassInfo::VariableArguments;
  }
  if (isReferenceVariableArgument()) {
    attribute |= ClassInfo::RefVariableArguments;
  }
  if (isMixedVariableArgument()) {
    attribute |= ClassInfo::MixedVariableArguments;
  }

  attribute |= m_attributeClassInfo;
  if (!m_docComment.empty() && Option::GenerateDocComments) {
    attribute |= ClassInfo::HasDocComment;
  } else {
    attribute &= ~ClassInfo::HasDocComment;
  }

  // Use the original cased name, for reflection to work correctly.
  cg_printf("(const char *)0x%04X, \"%s\", \"%s\", (const char *)%d, "
            "(const char *)%d, NULL, NULL,\n", attribute,
            getOriginalName().c_str(),
            m_stmt ? m_stmt->getLocation()->file : "",
            m_stmt ? m_stmt->getLocation()->line0 : 0,
            m_stmt ? m_stmt->getLocation()->line1 : 0);

  if (!m_docComment.empty() && Option::GenerateDocComments) {
    char *dc = string_cplus_escape(m_docComment.c_str(), m_docComment.size());
    cg_printf("\"%s\",\n", dc);
    free(dc);
  }

  Variant defArg;
  for (int i = 0; i < m_maxParam; i++) {
    int attr = ClassInfo::IsNothing;
    if (i >= m_minParam) attr |= ClassInfo::IsOptional;
    if (isRefParam(i)) attr |= ClassInfo::IsReference;

    const std::string &tname = m_paramTypeSpecs[i] ?
      m_paramTypeSpecs[i]->getPHPName() : "";
    cg_printf("(const char *)0x%04X, \"%s\", \"%s\", ",
              attr, m_paramNames[i].c_str(),
              Util::toLower(tname).c_str());

    if (i >= m_minParam) {
      MethodStatementPtr m =
        dynamic_pointer_cast<MethodStatement>(getStmt());
      if (m) {
        ExpressionListPtr params = m->getParams();
        assert(i < params->getCount());
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*params)[i]);
        assert(param);
        ExpressionPtr def = param->defaultValue();
        string sdef = def->getText();
        char *esdef = string_cplus_escape(sdef.data(), sdef.size());
        if (!def->isScalar() || !def->getScalarValue(defArg)) {
          /**
           * Special value runtime/ext/ext_reflection.cpp can check and throw.
           * If we want to avoid seeing this so to make getDefaultValue()
           * work better for reflections, we will have to implement
           * getScalarValue() to greater extent under compiler/expressions.
           */
          cg_printf("\"\x01\", \"%s\",\n", esdef);
        } else {
          String str = f_serialize(defArg);
          char *s = string_cplus_escape(str.data(), str.size());
          cg_printf("\"%s\", \"%s\",\n", s, esdef);
          free(s);
        }
        free(esdef);
      } else {
        char *def = string_cplus_escape(m_paramDefaults[i].data(),
                                        m_paramDefaults[i].size());
        char *defText = string_cplus_escape(m_paramDefaultTexts[i].data(),
                                            m_paramDefaultTexts[i].size());
        cg_printf("\"%s\", \"%s\",\n", def, defText);
        free(def);
        free(defText);
      }
    } else {
      cg_printf("\"\", \"\",\n");
    }
  }
  cg_printf("NULL,\n");

  m_variables->outputCPPStaticVariables(cg, ar);
}
Beispiel #30
0
void MethodStatement::inferFunctionTypes(AnalysisResultPtr ar) {
  IMPLEMENT_INFER_AND_CHECK_ASSERT(getFunctionScope());

  FunctionScopeRawPtr funcScope = getFunctionScope();
  bool pseudoMain = funcScope->inPseudoMain();

  if (m_stmt && funcScope->isFirstPass()) {
    if (pseudoMain ||
        funcScope->getReturnType() ||
        m_stmt->hasRetExp()) {
      bool lastIsReturn = false;
      if (m_stmt->getCount()) {
        StatementPtr lastStmt = (*m_stmt)[m_stmt->getCount()-1];
        if (lastStmt->is(Statement::KindOfReturnStatement)) {
          lastIsReturn = true;
        }
      }
      if (!lastIsReturn) {
        ExpressionPtr constant =
          makeScalarExpression(ar, funcScope->inPseudoMain() ?
                               Variant(1) :
                               Variant(Variant::NullInit()));
        ReturnStatementPtr returnStmt =
          ReturnStatementPtr(
            new ReturnStatement(getScope(), getLocation(), constant));
        m_stmt->addElement(returnStmt);
      }
    }
  }

  if (m_params) {
    m_params->inferAndCheck(ar, Type::Any, false);
  }

  // must also include params and use vars if this is a generator. note: we are
  // OK reading the params from the AST nodes of the original generator
  // function, since we have the dependency links set up
  if (funcScope->isGenerator()) {
    // orig function params
    MethodStatementRawPtr m = getOrigGeneratorFunc();
    assert(m);

    VariableTablePtr variables = funcScope->getVariables();
    ExpressionListPtr params = m->getParams();
    if (params) {
      for (int i = 0; i < params->getCount(); i++) {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*params)[i]);
        const string &name = param->getName();
        assert(!param->isRef() || param->getType()->is(Type::KindOfVariant));
        variables->addParamLike(name, param->getType(), ar, param,
                                funcScope->isFirstPass());
      }
    }

    // use vars
    ExpressionListPtr useVars = m->getFunctionScope()->getClosureVars();
    if (useVars) {
      for (int i = 0; i < useVars->getCount(); i++) {
        ParameterExpressionPtr param =
          dynamic_pointer_cast<ParameterExpression>((*useVars)[i]);
        const string &name = param->getName();
        assert(!param->isRef() || param->getType()->is(Type::KindOfVariant));
        variables->addParamLike(name, param->getType(), ar, param,
                                funcScope->isFirstPass());
      }
    }
  }

  if (m_stmt) {
    m_stmt->inferTypes(ar);
  }
}