コード例 #1
0
ArrayElementExpression::ArrayElementExpression
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
 ExpressionPtr variable, ExpressionPtr offset)
  : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES),
    m_variable(variable), m_offset(offset), m_global(false),
    m_dynamicGlobal(false), m_localEffects(AccessorEffect) {
  m_variable->setContext(Expression::AccessContext);

  if (m_variable->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr var =
      dynamic_pointer_cast<SimpleVariable>(m_variable);
    if (var->getName() == "GLOBALS") {
      m_global = true;
      m_dynamicGlobal = true;
      if (m_offset && m_offset->is(Expression::KindOfScalarExpression)) {
        ScalarExpressionPtr offset =
          dynamic_pointer_cast<ScalarExpression>(m_offset);

        if (offset->isLiteralString()) {
          m_globalName = offset->getIdentifier();
          if (!m_globalName.empty()) {
            m_dynamicGlobal = false;
          }
        }
      }
    }
  }
}
コード例 #2
0
void SwitchStatement::analyzeProgramImpl(AnalysisResultPtr ar) {
  m_exp->analyzeProgram(ar);
  if (m_cases) m_cases->analyzeProgram(ar);

  if (ar->getPhase() == AnalysisResult::AnalyzeAll &&
      m_exp->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr exp = dynamic_pointer_cast<SimpleVariable>(m_exp);
    if (exp && exp->getSymbol() && exp->getSymbol()->isClassName()) {
      // Mark some classes as volitle since the name is used in switch
      for (int i = 0; i < m_cases->getCount(); i++) {
        CaseStatementPtr stmt =
          dynamic_pointer_cast<CaseStatement>((*m_cases)[i]);
        ASSERT(stmt);
        ExpressionPtr caseCond = stmt->getCondition();
        if (caseCond && caseCond->isScalar()) {
          ScalarExpressionPtr name =
            dynamic_pointer_cast<ScalarExpression>(caseCond);
          if (name && name->isLiteralString()) {
            string className = name->getLiteralString();
            ClassScopePtr cls = ar->findClass(Util::toLower(className));
            if (cls && cls->isUserClass()) {
              cls->setVolatile();
            }
          }
        }
      }
      // Also note this down as code error
      ConstructPtr self = shared_from_this();
      Compiler::Error(Compiler::ConditionalClassLoading, self);
    }
  }
}
コード例 #3
0
bool BinaryOpExpression::outputCPPImplOpEqual(CodeGenerator &cg,
                                              AnalysisResultPtr ar) {
  if (m_exp1->is(Expression::KindOfArrayElementExpression)) {
    ArrayElementExpressionPtr exp =
      dynamic_pointer_cast<ArrayElementExpression>(m_exp1);
    if (exp->isSuperGlobal() || exp->isDynamicGlobal()) return false;
    if (TypePtr t = exp->getVariable()->getActualType()) {
      TypePtr it(exp->getVariable()->getImplementedType());
      if (t->is(Type::KindOfArray) &&
          (!it ||
           it->is(Type::KindOfArray) ||
           Type::IsMappedToVariant(it) /* fast cast will kick in */)) {
        return false;
      }
    }
    // turning $a['elem'] Op= $b into $a.setOpEqual('elem', $b);
    exp->getVariable()->outputCPP(cg, ar);
    if (exp->getOffset()) {
      cg_printf(".setOpEqual(%d, ", m_op);
      exp->getOffset()->outputCPP(cg, ar);
      cg_printf(", (");
    } else {
      cg_printf(".appendOpEqual(%d, (", m_op);
    }
    m_exp2->outputCPP(cg, ar);
    cg_printf(")");
    ExpressionPtr off = exp->getOffset();
    if (off) {
      ScalarExpressionPtr sc = dynamic_pointer_cast<ScalarExpression>(off);
      if (sc) {
        if (sc->isLiteralString()) {
          String s(sc->getLiteralString());
          int64 n;
          if (!s.get()->isStrictlyInteger(n)) {
            cg_printf(", true"); // skip toKey() at run time
          }
        }
      }
    }
    cg_printf(")");

    return true;
  }
  if (m_exp1->is(Expression::KindOfObjectPropertyExpression)) {
    ObjectPropertyExpressionPtr var(
      dynamic_pointer_cast<ObjectPropertyExpression>(m_exp1));
    if (var->isValid()) return false;
    var->outputCPPObject(cg, ar);
    cg_printf("o_assign_op<%s,%d>(",
              isUnused() ? "void" : "Variant", m_op);
    var->outputCPPProperty(cg, ar);
    cg_printf(", ");
    m_exp2->outputCPP(cg, ar);
    cg_printf("%s)", originalClassName(cg, true).c_str());
    return true;
  }

  return false;
}
コード例 #4
0
ファイル: option.cpp プロジェクト: Neomeng/hiphop-php
bool Option::Load(string &option, ExpressionPtr value) {
  ScalarExpressionPtr v = dynamic_pointer_cast<ScalarExpression>(value);
  if (!v || !v->isLiteralString()) {
    Logger::Error("Line %d: invalid string: %s", value->getLocation()->line1,
                  value->getText().c_str());
    return false;
  }
  option = v->getLiteralString();
  return true;
}
コード例 #5
0
bool BinaryOpExpression::outputCPPImplOpEqual(CodeGenerator &cg,
                                              AnalysisResultPtr ar) {
  if (!m_exp1->is(Expression::KindOfArrayElementExpression)) return false;
  ArrayElementExpressionPtr exp =
    dynamic_pointer_cast<ArrayElementExpression>(m_exp1);
  if (exp->isSuperGlobal() || exp->isDynamicGlobal()) return false;
  bool linemap = outputLineMap(cg, ar);

  // turning $a['elem'] Op= $b into $a.setOpEqual('elem', $b);
  exp->getVariable()->outputCPP(cg, ar);
  if (exp->getOffset()) {
    cg_printf(".setOpEqual(%d, ", m_op);
    exp->getOffset()->outputCPP(cg, ar);
    cg_printf(", (");
  } else {
    cg_printf(".appendOpEqual(%d, (", m_op);
  }
  m_exp2->outputCPP(cg, ar);
  cg_printf(")");
  ExpressionPtr off = exp->getOffset();
  if (off) {
    ScalarExpressionPtr sc = dynamic_pointer_cast<ScalarExpression>(off);
    if (sc) {
      int64 hash = sc->getHash();
      if (hash >= 0) {
        cg_printf(", 0x%016llXLL", hash);
      } else {
        cg_printf(", -1");
      }
      if (sc->isLiteralString()) {
        String s(sc->getLiteralString());
        int64 n;
        if (!s.get()->isStrictlyInteger(n)) {
          cg_printf(", true"); // skip toKey() at run time
        }
      }
    }
  }
  cg_printf(")");

  if (linemap) cg_printf(")");
  return true;
}
コード例 #6
0
void ArrayElementExpression::outputCPPExistTest(CodeGenerator &cg,
        AnalysisResultPtr ar, int op) {
    switch (op) {
    case T_ISSET:
        cg_printf("isset(");
        break;
    case T_EMPTY:
        cg_printf("empty(");
        break;
    default:
        ASSERT(false);
    }

    if (m_global) {
        if (!m_globalName.empty()) {
            VariableTablePtr variables = getScope()->getVariables();
            string name = variables->getGlobalVariableName(cg, ar, m_globalName);
            cg_printf("g->%s", name.c_str());
        } else {
            cg_printf("((LVariableTable *)g)->get(");
            m_offset->outputCPP(cg, ar);
            cg_printf(")");
        }
    } else {
        m_variable->outputCPP(cg, ar);
        cg_printf(", ");
        m_offset->outputCPP(cg, ar);
        ScalarExpressionPtr sc =
            dynamic_pointer_cast<ScalarExpression>(m_offset);
        if (sc) {
            if (sc->isLiteralString()) {
                String s(sc->getLiteralString());
                int64 n;
                if (!s.get()->isStrictlyInteger(n)) {
                    cg_printf(", true"); // skip toKey() at run time
                }
            }
        }
    }
    cg_printf(")");
}
コード例 #7
0
ファイル: option.cpp プロジェクト: Neomeng/hiphop-php
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;
}
コード例 #8
0
bool ArrayPairExpression::outputCPPName(CodeGenerator &cg,
                                        AnalysisResultPtr ar) {
  assert(m_name);
  ScalarExpressionPtr sc = dynamic_pointer_cast<ScalarExpression>(m_name);
  if (sc) {
    if (sc->isLiteralString()) {
      string s = sc->getLiteralString();
      int64 res;
      if (is_strictly_integer(s.c_str(), s.size(), res)) {
        cg_printf("%sL", s.c_str());
      } else {
        m_name->outputCPP(cg, ar);
      }
      return true;
    }
    if (sc->isLiteralInteger()) {
      m_name->outputCPP(cg, ar);
      return true;
    }
  }
  m_name->outputCPP(cg, ar);
  return false;
}
コード例 #9
0
void ArrayElementExpression::outputCPPUnset(CodeGenerator &cg,
                                            AnalysisResultPtr ar) {
  if (isSuperGlobal()) {
    Expression::outputCPPUnset(cg, ar);
  } else {
    TypePtr expected = m_variable->getExpectedType();
    TypePtr implemented = m_variable->getImplementedType();
    bool wrap = false;
    if (TypePtr t = m_variable->getActualType()) {
      if (t->is(Type::KindOfObject)) {
        if (!m_variable->getImplementedType() ||
            !m_variable->getImplementedType()->is(Type::KindOfVariant)) {
          cg_printf("((Variant)(");
          wrap = true;
        }
        m_variable->setImplementedType(TypePtr());
        m_variable->setExpectedType(TypePtr());
      }
    }
    m_variable->outputCPP(cg, ar);
    if (wrap) cg_printf("))");
    m_variable->setExpectedType(expected);
    m_variable->setImplementedType(implemented);
    cg_printf(".weakRemove(");
    m_offset->outputCPP(cg, ar);
    ScalarExpressionPtr sc =
      dynamic_pointer_cast<ScalarExpression>(m_offset);
    if (sc && sc->isLiteralString()) {
      String s(sc->getLiteralString());
      int64 n;
      if (!s->isStrictlyInteger(n)) {
        cg_printf(", true");
      }
    }
    cg_printf(")");
  }
}
コード例 #10
0
void ArrayElementExpression::outputCPPImpl(CodeGenerator &cg,
                                           AnalysisResultPtr ar) {
  if (m_global) {
    if (!m_globalName.empty()) {
      VariableTablePtr variables = getScope()->getVariables();
      string name = variables->getGlobalVariableName(cg, ar, m_globalName);
      cg_printf("g->%s", name.c_str());
    } else {
      cg_printf("((LVariableTable *)g)->get(");
      m_offset->outputCPP(cg, ar);
      cg_printf(")");
    }
  } else {
    TypePtr type = m_variable->getActualType();
    if (hasContext(UnsetContext)) {
      cg_printf("unsetLval(");
      m_variable->outputCPP(cg, ar);
      cg_printf(", ");
    } else {
      if (m_variable->is(Expression::KindOfScalarExpression) ||
          (type && (type->isInteger() ||
                    type->is(Type::KindOfDouble) ||
                    type->is(Type::KindOfObject) ||
                    type->is(Type::KindOfBoolean)))) {
        cg_printf(type && type->is(Type::KindOfString) ? "((String)" :
                  "((Variant)");
        m_variable->outputCPP(cg, ar);
        cg_printf(")");
      } else {
        TypePtr act;
        if (!m_variable->hasCPPTemp() && m_variable->getImplementedType() &&
            type->is(Type::KindOfArray) &&
            !Type::SameType(m_variable->getImplementedType(), type)) {
          act = type;
          type = m_variable->getImplementedType();
          m_variable->setActualType(m_variable->getImplementedType());
        }
        m_variable->outputCPP(cg, ar);
        if (act) {
          m_variable->setActualType(act);
        }
      }
    }
    if (m_offset) {
      bool lvalAt = false;
      bool rvalAt = false;
      bool byRef = false;
      bool arrRef = false;
      const char *sep = ", AccessFlags::";
      if (hasContext(UnsetContext)) {
        // do nothing
      } else if (hasContext(InvokeArgument) && cg.callInfoTop() != -1) {
        cg_printf(".argvalAt(cit%d->isRef(%d), ", cg.callInfoTop(), m_argNum);
      } else if (m_context & (LValue|RefValue|DeepReference)) {
        cg_printf(".lvalAt(");
        lvalAt = true;
      } else {
        byRef = (m_context & AccessContext) &&
          (!type || !type->is(Type::KindOfString));
        arrRef = byRef && type && type->is(Type::KindOfArray);
        cg_printf(".rval%s%s(",
                  arrRef || !byRef ? "At" : "", byRef ? "Ref" : "");
        rvalAt = true;
      }
      m_offset->outputCPP(cg, ar);
      if (!type || !type->is(Type::KindOfString)) {
        if (rvalAt) {
          if (byRef && !arrRef) {
            const string &tmp = cg.getReferenceTemp();
            cg_printf(", %s", tmp.empty() ? "Variant()" : tmp.c_str());
          }
          if (!hasContext(ExistContext)) {
            cg_printf(", AccessFlags::Error"); // raise undefined index error
            sep = "_";
          }
        } else if (lvalAt) {
          if (hasContext(AccessContext)) {
            // Dont copy the array if the element is an object, or
            // is referenced.
            // This is safe in AccessContext (the parent is an ArrayElement,
            // or an ObjectProperty) because applying [] to an object will
            // either invoke OffsetGet, or fatal, and modifications to a
            // referenced element would be reflected in all copies
            // of the array anyway.
            cg_printf(", AccessFlags::CheckExist");
            sep = "_";
          }
        }
        ScalarExpressionPtr sc =
          dynamic_pointer_cast<ScalarExpression>(m_offset);
        if (!hasContext(UnsetContext) && sc && sc->isLiteralString()) {
          String s(sc->getLiteralString());
          int64 n;
          if (!s.get()->isStrictlyInteger(n)) {
            if (lvalAt || rvalAt) {
              cg_printf("%sKey", sep);
            } else {
              cg_printf(", true"); // skip toKey() at run time
            }
          }
        }
      }
      cg_printf(")");
    } else {
      cg_printf(".lvalAt()");
    }
  }
}
コード例 #11
0
/**
 * ArrayElementExpression comes from:
 *
 * reference_variable[|expr]
 * ->object_dim_list[|expr]
 * encaps T_VARIABLE[expr]
 * encaps ${T_STRING[expr]}
 */
TypePtr ArrayElementExpression::inferTypes(AnalysisResultPtr ar,
                                           TypePtr type, bool coerce) {
  ConstructPtr self = shared_from_this();

  if (m_offset &&
      !(m_context & (UnsetContext | ExistContext |
                     InvokeArgument | LValue | RefValue))) {
    setEffect(DiagnosticEffect);
  }
  if (m_context & (AssignmentLHS|OprLValue)) {
    clearEffect(AccessorEffect);
  } else if (m_context & (LValue | RefValue)) {
    setEffect(CreateEffect);
  }

  // handling $GLOBALS[...]
  if (m_variable->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr var =
      dynamic_pointer_cast<SimpleVariable>(m_variable);
    if (var->getName() == "GLOBALS") {
      clearEffect(AccessorEffect);
      m_global = true;
      m_dynamicGlobal = true;
      getScope()->getVariables()->
        setAttribute(VariableTable::NeedGlobalPointer);
      VariableTablePtr vars = ar->getVariables();

      if (m_offset && m_offset->is(Expression::KindOfScalarExpression)) {
        ScalarExpressionPtr offset =
          dynamic_pointer_cast<ScalarExpression>(m_offset);

        if (offset->isLiteralString()) {
          m_globalName = offset->getIdentifier();
          if (!m_globalName.empty()) {
            m_dynamicGlobal = false;
            clearEffect(DiagnosticEffect);
            getScope()->getVariables()->
              setAttribute(VariableTable::NeedGlobalPointer);
            TypePtr ret;
            if (coerce) {
              ret = vars->add(m_globalName, type, true, ar, self,
                              ModifierExpressionPtr());
            } else {
              int p;
              ret =
                vars->checkVariable(m_globalName, type, coerce, ar, self, p);
            }
            getScope()->getVariables()->addSuperGlobal(m_globalName);
            return ret;
          }
        }
      } else {
        vars->setAttribute(VariableTable::ContainsDynamicVariable);
      }

      if (hasContext(LValue) || hasContext(RefValue)) {
        ar->getVariables()->forceVariants(ar, VariableTable::AnyVars);
        ar->getVariables()->
          setAttribute(VariableTable::ContainsLDynamicVariable);
      }
      if (m_offset) {
        m_offset->inferAndCheck(ar, Type::Primitive, false);
      }
      return m_implementedType = Type::Variant; // so not to lose values
    }
  }
  if ((hasContext(LValue) || hasContext(RefValue)) &&
      !hasContext(UnsetContext)) {
    m_variable->setContext(LValue);
  }

  TypePtr varType;
  if (m_offset) {
    varType = m_variable->inferAndCheck(ar, coerce ? Type::AutoSequence :
                                        Type::Sequence, coerce);
    m_offset->inferAndCheck(ar, Type::Some, false);
  } else {
    if (hasContext(ExistContext) || hasContext(UnsetContext)) {
      if (getScope()->isFirstPass()) {
        Compiler::Error(Compiler::InvalidArrayElement, self);
      }
    }
    m_variable->inferAndCheck(ar, Type::Array, true);
  }

  if (varType && Type::SameType(varType, Type::String)) {
    clearEffect(AccessorEffect);
    m_implementedType.reset();
    return Type::String;
  }

  if (varType && Type::SameType(varType, Type::Array)) {
    clearEffect(AccessorEffect);
  }

  TypePtr ret = propagateTypes(ar, Type::Variant);
  m_implementedType = Type::Variant;
  return ret; // so not to lose values
}
コード例 #12
0
void AssignmentExpression::outputCPPImpl(CodeGenerator &cg,
                                         AnalysisResultPtr ar) {
  BlockScopePtr scope = ar->getScope();
  bool ref = (m_ref && !m_value->is(Expression::KindOfNewObjectExpression));

  bool setElement = false; // turning $a['elem'] = $b into $a.set('elem', $b);
  bool type_cast = false;
  bool setNull = false;
  TypePtr m_actualType;

  if (m_variable->is(Expression::KindOfArrayElementExpression)) {
    ArrayElementExpressionPtr exp =
      dynamic_pointer_cast<ArrayElementExpression>(m_variable);
    m_actualType = m_variable->getActualType();
    if (m_actualType && m_actualType->getKindOf() == Type::KindOfVariant
        && !ref) {
      //type_cast = true;
    }
    if (!exp->isSuperGlobal() && !exp->isDynamicGlobal()) {
      exp->getVariable()->outputCPP(cg, ar);
      if (exp->getOffset()) {
        cg.printf(".set(");
        exp->getOffset()->outputCPP(cg, ar);
        cg.printf(", (");
      } else {
        cg.printf(".append((");
      }
      if (type_cast) {
        m_actualType->outputCPPCast(cg, ar);
        cg.printf("(");
      }
      if (ref && m_value->isRefable()) cg.printf("ref(");
      m_value->outputCPP(cg, ar);
      if (ref && m_value->isRefable()) cg.printf(")");
      if (type_cast) cg.printf(")");
      cg.printf(")");
      ExpressionPtr off = exp->getOffset();
      if (off) {
        ScalarExpressionPtr sc =
          dynamic_pointer_cast<ScalarExpression>(off);
        if (sc) {
          int64 hash = sc->getHash();
          if (hash >= 0) {
            cg.printf(", 0x%016llXLL", hash);
          } else {
            cg.printf(", -1");
          }
          if (sc->isLiteralString()) {
            String s(sc->getLiteralString());
            int64 n;
            if (!s.get()->isStrictlyInteger(n)) {
              cg.printf(", true"); // skip toKey() at run time
            }
          }
        }
      }
      cg.printf(")");
      setElement = true;
    }
  }
  if (m_variable->is(Expression::KindOfSimpleVariable) &&
      m_value->is(Expression::KindOfConstantExpression)) {
    ConstantExpressionPtr exp =
      dynamic_pointer_cast<ConstantExpression>(m_value);
    if (exp->isNull()) setNull = true;
  }

  if (!setElement) {
    if (setNull) {
      cg.printf("setNull(");
      m_variable->outputCPP(cg, ar);
    } else {
      cg.printf("(");
      m_variable->outputCPP(cg, ar);
      cg.printf(" = ");

      if (type_cast) {
        m_actualType->outputCPPCast(cg, ar);
        cg.printf("(");
      }
      if (ref && m_value->isRefable()) cg.printf("ref(");
      m_value->outputCPP(cg, ar);
      if (ref && m_value->isRefable()) cg.printf(")");
      if (type_cast) cg.printf(")");
    }
    cg.printf(")");
  }
}
コード例 #13
0
void SimpleFunctionCall::outputCPPImpl(CodeGenerator &cg,
                                       AnalysisResultPtr ar) {
  bool linemap = outputLineMap(cg, ar, true);

  if (!m_lambda.empty()) {
    cg.printf("\"%s\"", m_lambda.c_str());
    if (linemap) cg.printf(")");
    return;
  }

  if (m_className.empty()) {
    if (m_type == DefineFunction && m_params && m_params->getCount() >= 2) {
      ScalarExpressionPtr name =
        dynamic_pointer_cast<ScalarExpression>((*m_params)[0]);
      string varName;
      if (name) {
        varName = name->getIdentifier();
        ExpressionPtr value = (*m_params)[1];
        if (varName.empty()) {
          cg.printf("throw_fatal(\"bad define\")");
        } else if (m_dynamicConstant) {
          cg.printf("g->declareConstant(\"%s\", g->%s%s, ",
                    varName.c_str(), Option::ConstantPrefix,
                    varName.c_str());
          value->outputCPP(cg, ar);
          cg.printf(")");
        } else {
          bool needAssignment = true;
          bool isSystem = ar->getConstants()->isSystem(varName);
          if (isSystem ||
              ((!ar->isConstantRedeclared(varName)) && value->isScalar())) {
            needAssignment = false;
          }
          if (needAssignment) {
            cg.printf("%s%s = ", Option::ConstantPrefix, varName.c_str());
            value->outputCPP(cg, ar);
          }
        }
      } else {
        cg.printf("throw_fatal(\"bad define\")");
      }
      if (linemap) cg.printf(")");
      return;
    }
    if (m_name == "func_num_args") {
      cg.printf("num_args");
      if (linemap) cg.printf(")");
      return;
    }

    switch (m_type) {
    case VariableArgumentFunction:
      {
        FunctionScopePtr func =
          dynamic_pointer_cast<FunctionScope>(ar->getScope());
        if (func) {
          cg.printf("%s(", m_name.c_str());
          func->outputCPPParamsCall(cg, ar, true);
          if (m_params) {
            cg.printf(",");
            m_params->outputCPP(cg, ar);
          }
          cg.printf(")");
          if (linemap) cg.printf(")");
          return;
        }
      }
      break;
    case FunctionExistsFunction:
    case ClassExistsFunction:
    case InterfaceExistsFunction:
      {
        bool literalString = false;
        string symbol;
        if (m_params && m_params->getCount() == 1) {
          ExpressionPtr value = (*m_params)[0];
          if (value->isScalar()) {
            ScalarExpressionPtr name =
              dynamic_pointer_cast<ScalarExpression>(value);
            if (name && name->isLiteralString()) {
              literalString = true;
              symbol = name->getLiteralString();
            }
          }
        }
        if (literalString) {
          switch (m_type) {
          case FunctionExistsFunction:
            {
              const std::string &lname = Util::toLower(symbol);
              bool dynInvoke = Option::DynamicInvokeFunctions.find(lname) !=
                Option::DynamicInvokeFunctions.end();
              if (!dynInvoke) {
                FunctionScopePtr func = ar->findFunction(lname);
                if (func) {
                  if (!func->isDynamic()) {
                    if (func->isRedeclaring()) {
                      const char *name = func->getName().c_str();
                      cg.printf("(%s->%s%s != invoke_failed_%s)",
                                cg.getGlobals(ar), Option::InvokePrefix,
                                name, name);
                      break;
                    }
                    cg.printf("true");
                    break;
                  }
                } else {
                  cg.printf("false");
                  break;
                }
              }
              cg.printf("f_function_exists(\"%s\")", lname.c_str());
            }
            break;
          case ClassExistsFunction:
            {
              ClassScopePtr cls = ar->findClass(Util::toLower(symbol));
              if (cls && !cls->isInterface()) {
                const char *name = cls->getName().c_str();
                cg.printf("f_class_exists(\"%s\")", name);
              } else {
                cg.printf("false");
              }
            }
            break;
          case InterfaceExistsFunction:
            {
              ClassScopePtr cls = ar->findClass(Util::toLower(symbol));
              if (cls && cls->isInterface()) {
                const char *name = cls->getName().c_str();
                cg.printf("f_interface_exists(\"%s\")", name);
              } else {
                cg.printf("false");
              }
            }
            break;
          default:
            break;
          }
          if (linemap) cg.printf(")");
          return;
        }
      }
      break;
    case GetDefinedVarsFunction:
      cg.printf("get_defined_vars(variables)");
      if (linemap) cg.printf(")");
      return;
    default:
      break;
    }
  }

  outputCPPParamOrderControlled(cg, ar);
  if (linemap) cg.printf(")");
}
コード例 #14
0
/**
 * ArrayElementExpression comes from:
 *
 * reference_variable[|expr]
 * ->object_dim_list[|expr]
 * encaps T_VARIABLE[expr]
 * encaps ${T_STRING[expr]}
 */
TypePtr ArrayElementExpression::inferTypes(AnalysisResultPtr ar,
                                           TypePtr type, bool coerce) {
  ConstructPtr self = shared_from_this();

  // handling $GLOBALS[...]
  if (m_variable->is(Expression::KindOfSimpleVariable)) {
    SimpleVariablePtr var =
      dynamic_pointer_cast<SimpleVariable>(m_variable);
    if (var->getName() == "GLOBALS") {
      clearEffect(AccessorEffect);
      m_global = true;
      m_dynamicGlobal = true;
      ar->getScope()->getVariables()->
        setAttribute(VariableTable::NeedGlobalPointer);
      VariableTablePtr vars = ar->getVariables();


      if (m_offset && m_offset->is(Expression::KindOfScalarExpression)) {
        ScalarExpressionPtr offset =
          dynamic_pointer_cast<ScalarExpression>(m_offset);

        if (offset->isLiteralString()) {
          m_globalName = offset->getIdentifier();
          if (!m_globalName.empty()) {
            m_dynamicGlobal = false;
            ar->getScope()->getVariables()->
              setAttribute(VariableTable::NeedGlobalPointer);
            TypePtr ret;
            ConstructPtr decl = vars->getDeclaration(m_globalName);
            if (decl) {
              ar->getDependencyGraph()->
                add(DependencyGraph::KindOfGlobalVariable,
                    ar->getName(),
                    m_globalName, self, m_globalName, decl);
            }
            if (coerce) {
              ret = vars->add(m_globalName, type, true, ar, self,
                              ModifierExpressionPtr());
            } else {
              int p;
              ret =
                vars->checkVariable(m_globalName, type, coerce, ar, self, p);
            }
            ar->getScope()->getVariables()->addSuperGlobal(m_globalName);
            return ret;
          }
        }
      } else {
        vars->setAttribute(VariableTable::ContainsDynamicVariable);
      }


      if (hasContext(LValue) || hasContext(RefValue)) {
        if (ar->isFirstPass()) {
          ar->getCodeError()->record(self, CodeError::UseLDynamicVariable,
                                     self);
        }
        ar->getVariables()->forceVariants(ar);
        ar->getVariables()->
          setAttribute(VariableTable::ContainsLDynamicVariable);
      } else {
        if (ar->isFirstPass()) {
          ar->getCodeError()->record(self, CodeError::UseRDynamicVariable,
                                     self);
        }
      }
      if (m_offset) {
        m_offset->inferAndCheck(ar, NEW_TYPE(Primitive), false);
      }
      return m_implementedType = Type::Variant; // so not to lose values
    }
  }
  if ((hasContext(LValue) || hasContext(RefValue)) &&
      !hasContext(UnsetContext)) {
    m_variable->setContext(LValue);
  }

  TypePtr varType;
  if (m_offset) {
    varType = m_variable->inferAndCheck(ar, NEW_TYPE(Sequence), false);
    m_offset->inferAndCheck(ar, NEW_TYPE(Some), false);
  } else {
    if (hasContext(ExistContext) || hasContext(UnsetContext)) {
      if (ar->isFirstPass()) {
        ar->getCodeError()->record(self, CodeError::InvalidArrayElement,
                                   self);
      }
    }
    m_variable->inferAndCheck(ar, Type::Array, true);
  }

  if (varType && Type::SameType(varType, Type::String)) {
    clearEffect(AccessorEffect);
    m_implementedType.reset();
    return Type::String;
  }

  if (varType && Type::SameType(varType, Type::Array)) {
    clearEffect(AccessorEffect);
  }

  if (hasContext(LValue) || hasContext(RefValue)) setEffect(CreateEffect);

  TypePtr ret = propagateTypes(ar, Type::Variant);
  m_implementedType = Type::Variant;
  return ret; // so not to lose values
}
コード例 #15
0
ファイル: case_statement.cpp プロジェクト: dolfly/hhvm
bool CaseStatement::isLiteralString() const {
    if (!m_condition->is(Expression::KindOfScalarExpression)) return false;
    ScalarExpressionPtr exp =
        dynamic_pointer_cast<ScalarExpression>(m_condition);
    return exp->isLiteralString();
}
コード例 #16
0
void AssignmentExpression::outputCPPImpl(CodeGenerator &cg,
                                         AnalysisResultPtr ar) {
  BlockScopePtr scope = ar->getScope();
  bool ref = (m_ref && m_value->isRefable());

  bool setNull = false;
  bool arrayLike = false;

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

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

    wrapValue(cg, ar, m_value, ref, arrayLike);
  }
  if (wrapped) {
    cg_printf(")");
  }
}
コード例 #17
0
void ArrayElementExpression::outputCPPImpl(CodeGenerator &cg,
                                           AnalysisResultPtr ar) {
  if (m_global) {
    if (!m_globalName.empty()) {
      VariableTablePtr variables = getScope()->getVariables();
      string name = variables->getGlobalVariableName(ar, m_globalName);
      cg_printf("g->%s", name.c_str());
    } else {
      cg_printf("((LVariableTable *)g)->get(");
      m_offset->outputCPP(cg, ar);
      cg_printf(")");
    }
  } else {
    TypePtr type = m_variable->getType();
    if (hasContext(UnsetContext)) {
      cg_printf("unsetLval(");
      m_variable->outputCPP(cg, ar);
      cg_printf(", ");
    } else {
      if (m_variable->is(Expression::KindOfScalarExpression) ||
          (type && (type->isInteger() ||
                    type->is(Type::KindOfDouble) ||
                    type->is(Type::KindOfObject) ||
                    type->is(Type::KindOfBoolean)))) {
        cg_printf(type && type->is(Type::KindOfString) ? "((String)" :
                  "((Variant)");
        m_variable->outputCPP(cg, ar);
        cg_printf(")");
      } else {
        m_variable->outputCPP(cg, ar);
      }
    }
    if (m_offset) {
      bool lvalAt = false;
      bool rvalAt = false;
      bool byRef = false;
      bool arrRef = false;
      const char *sep = ", AccessFlags::";
      bool isArrayType = type && type->is(Type::KindOfArray);
      bool isStringType = type && type->is(Type::KindOfString);
      bool isRealChainRoot = isChainRoot() && hasCPPCseTemp();

      TypePtr t;
      bool hasCseStore = isRealChainRoot && GetCseTempInfo(
          ar,
          static_pointer_cast<Expression>(shared_from_this()),
          t);

      if (hasContext(UnsetContext)) {
        // do nothing
      } else if (hasContext(InvokeArgument) && cg.callInfoTop() != -1) {
        ASSERT(!isRealChainRoot); // TODO: handle this case
        cg_printf(".argvalAt(cit%d->isRef(%d), ", cg.callInfoTop(), m_argNum);
      } else if (m_context & (LValue|RefValue|DeepReference)) {
        // if we see an array access element in LValue context, the
        // type inference pass will never infer its type to be a string
        ASSERT(!isStringType);
        if (isRealChainRoot && !isArrayType) {
          // chain roots for non array types (variants) should call
          // lvalRef()
          cg_printf(".lvalRef(");
        } else {
          cg_printf(".lvalAt(");
        }
        lvalAt = true;
      } else {
        byRef =
          ((m_context & AccessContext) || isRealChainRoot) && !isStringType;
        arrRef = byRef && isArrayType;
        cg_printf(".rval%s%s(",
                  arrRef || !byRef ? "At" : "", byRef ? "Ref" : "");
        rvalAt = true;
      }
      m_offset->outputCPP(cg, ar);
      if (!isStringType) {
        if (rvalAt) {
          if (byRef && !arrRef) {
            string tmp;
            if (hasCseStore) {
              tmp = string(Option::CseTempStoragePrefix) + m_cppCseTemp;
            } else {
              tmp = cg.getReferenceTemp();
            }
            cg_printf(", %s", tmp.empty() ? "Variant()" : tmp.c_str());
          }
          if (!hasContext(ExistContext)) {
            cg_printf(", AccessFlags::Error"); // raise undefined index error
            sep = "_";
          }
        } else if (lvalAt) {
          if (hasCseStore && !isArrayType) {
            cg_printf(", %s%s",
                Option::CseTempStoragePrefix, m_cppCseTemp.c_str());
          }
          if (hasContext(AccessContext)) {
            // Dont copy the array if the element is an object, or
            // is referenced.
            // This is safe in AccessContext (the parent is an ArrayElement,
            // or an ObjectProperty) because applying [] to an object will
            // either invoke OffsetGet, or fatal, and modifications to a
            // referenced element would be reflected in all copies
            // of the array anyway.
            cg_printf(", AccessFlags::CheckExist");
            sep = "_";
          }
        }
        ScalarExpressionPtr sc =
          dynamic_pointer_cast<ScalarExpression>(m_offset);
        if (!hasContext(UnsetContext) && sc && sc->isLiteralString()) {
          String s(sc->getLiteralString());
          int64 n;
          if (!s.get()->isStrictlyInteger(n)) {
            if (lvalAt || rvalAt) {
              cg_printf("%sKey", sep);
            } else {
              cg_printf(", true"); // skip toKey() at run time
            }
          }
        }
      }
      cg_printf(")");
    } else {
      cg_printf(".lvalAt()");
    }
  }
}
コード例 #18
0
bool AssignmentExpression::SpecialAssignment(CodeGenerator &cg,
                                             AnalysisResultPtr ar,
                                             ExpressionPtr lval,
                                             ExpressionPtr rval,
                                             const char *rvalStr, bool ref) {
  if (lval->is(KindOfArrayElementExpression)) {
    ArrayElementExpressionPtr exp =
      dynamic_pointer_cast<ArrayElementExpression>(lval);
    if (!exp->isSuperGlobal() && !exp->isDynamicGlobal()) {
      exp->getVariable()->outputCPP(cg, ar);
      if (exp->getOffset()) {
        cg_printf(".set(");
        exp->getOffset()->outputCPP(cg, ar);
        cg_printf(", (");
      } else {
        cg_printf(".append((");
      }
      if (rval) {
        wrapValue(cg, ar, rval, ref,
                  (exp->getVariable()->is(KindOfArrayElementExpression) ||
                   exp->getVariable()->is(KindOfObjectPropertyExpression)) &&
                  (exp->getVariable()->getContainedEffects() &&
                   (CreateEffect|AccessorEffect)));
      } else {
        cg_printf(ref ? "ref(%s)" : "%s", rvalStr);
      }
      cg_printf(")");
      ExpressionPtr off = exp->getOffset();
      if (off) {
        ScalarExpressionPtr sc =
          dynamic_pointer_cast<ScalarExpression>(off);
        if (sc) {
          if (sc->isLiteralString()) {
            String s(sc->getLiteralString());
            int64 n;
            if (!s.get()->isStrictlyInteger(n)) {
              cg_printf(", true"); // skip toKey() at run time
            }
          }
        }
      }
      cg_printf(")");
      return true;
    }
  } else if (lval->is(KindOfObjectPropertyExpression)) {
    ObjectPropertyExpressionPtr var(
      dynamic_pointer_cast<ObjectPropertyExpression>(lval));
    if (!var->isValid()) {
      bool nonPrivate = var->isNonPrivate(ar);
      var->outputCPPObject(cg, ar);
      if (nonPrivate) {
        cg_printf("o_setPublic(");
      } else {
        cg_printf("o_set(");
      }
      var->outputCPPProperty(cg, ar);
      cg_printf(", %s", ref ? "ref(" : "");
      if (rval) {
        rval->outputCPP(cg, ar);
      } else {
        cg_printf(ref ? "ref(%s)" : "%s", rvalStr);
      }
      if (nonPrivate) {
        cg_printf("%s)", ref ? ")" : "");
      }
      else {
        cg_printf("%s%s)",
                  ref ? ")" : "",
                  lval->originalClassName(cg, true).c_str());
      }
      return true;
    }
  }
  return false;
}
コード例 #19
0
void SimpleFunctionCall::analyzeProgram(AnalysisResultPtr ar) {
  if (m_className.empty()) {
    addUserFunction(ar, m_name);
  } else if (m_className != "parent") {
    addUserClass(ar, m_className);
  } else {
    m_parentClass = true;
  }

  if (ar->getPhase() == AnalysisResult::AnalyzeInclude) {

    CHECK_HOOK(onSimpleFunctionCallAnalyzeInclude);

    ConstructPtr self = shared_from_this();

    // We need to know the name of the constant so that we can associate it
    // with this file before we do type inference.
    if (m_className.empty() && m_type == DefineFunction) {
      ScalarExpressionPtr name =
        dynamic_pointer_cast<ScalarExpression>((*m_params)[0]);
      string varName;
      if (name) {
        varName = name->getIdentifier();
        if (!varName.empty()) {
          ar->getFileScope()->declareConstant(ar, varName);
        }
      }
      // handling define("CONSTANT", ...);
      if (m_params && m_params->getCount() >= 2) {
        ScalarExpressionPtr name =
          dynamic_pointer_cast<ScalarExpression>((*m_params)[0]);
        string varName;
        if (name) {
          varName = name->getIdentifier();
          if (!varName.empty()) {
            ExpressionPtr value = (*m_params)[1];
            ConstantTablePtr constants =
              ar->findConstantDeclarer(varName)->getConstants();
            if (constants != ar->getConstants()) {
              constants->add(varName, NEW_TYPE(Some), value, ar, self);

              if (name->hasHphpNote("Dynamic")) {
                constants->setDynamic(ar, varName);
              }
            }
          }
        }
      }
    }

    if (m_type == UnserializeFunction) {
      ar->forceClassVariants();
    }
  }

  if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
    // Look up the corresponding FunctionScope and ClassScope
    // for this function call
    {
      FunctionScopePtr func;
      ClassScopePtr cls;
      if (m_className.empty()) {
        func = ar->findFunction(m_name);
      } else {
        cls = ar->resolveClass(m_className);
        if (cls) {
          if (m_name == "__construct") {
            func = cls->findConstructor(ar, true);
          } else {
            func = cls->findFunction(ar, m_name, true, true);
          }
        }
      }
      if (func && !func->isRedeclaring()) {
        if (m_funcScope != func) {
          m_funcScope = func;
          Construct::recomputeEffects();
        }
      }
      if (cls && !cls->isRedeclaring())
        m_classScope = cls;
    }
    // check for dynamic constant and volatile function/class
    if (m_className.empty() &&
      (m_type == DefinedFunction ||
       m_type == FunctionExistsFunction ||
       m_type == ClassExistsFunction ||
       m_type == InterfaceExistsFunction) &&
      m_params && m_params->getCount() >= 1) {
      ExpressionPtr value = (*m_params)[0];
      if (value->isScalar()) {
        ScalarExpressionPtr name =
          dynamic_pointer_cast<ScalarExpression>(value);
        if (name && name->isLiteralString()) {
          string symbol = name->getLiteralString();
          switch (m_type) {
          case DefinedFunction: {
            ConstantTablePtr constants = ar->getConstants();
            if (!constants->isPresent(symbol)) {
              // user constant
              BlockScopePtr block = ar->findConstantDeclarer(symbol);
              if (block) { // found the constant
                constants = block->getConstants();
                // set to be dynamic
                constants->setDynamic(ar, symbol);
              }
            }
            break;
          }
          case FunctionExistsFunction: {
            FunctionScopePtr func = ar->findFunction(Util::toLower(symbol));
            if (func && func->isUserFunction()) {
              func->setVolatile();
            }
            break;
          }
          case InterfaceExistsFunction:
          case ClassExistsFunction: {
            ClassScopePtr cls = ar->findClass(Util::toLower(symbol));
            if (cls && cls->isUserClass()) {
              cls->setVolatile();
            }
            break;
          }
          default:
            ASSERT(false);
          }
        }
      }
    }
  }
  if (m_params) {
    if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
      if (m_funcScope) {
        ExpressionList &params = *m_params;
        int mpc = m_funcScope->getMaxParamCount();
        for (int i = params.getCount(); i--; ) {
          ExpressionPtr p = params[i];
          if (i < mpc ? m_funcScope->isRefParam(i) :
              m_funcScope->isReferenceVariableArgument()) {
            p->setContext(Expression::RefValue);
          } else if (!(p->getContext() & Expression::RefParameter)) {
            p->clearContext(Expression::RefValue);
          }
        }
      } else {
        FunctionScopePtr func = ar->findFunction(m_name);
        if (func && func->isRedeclaring()) {
          FunctionScope::RefParamInfoPtr info =
            FunctionScope::GetRefParamInfo(m_name);
          if (info) {
            for (int i = m_params->getCount(); i--; ) {
              if (info->isRefParam(i)) {
                m_params->markParam(i, canInvokeFewArgs());
              }
            }
          }
        } else {
          m_params->markParams(false);
        }
      }
    }

    m_params->analyzeProgram(ar);
  }
}
コード例 #20
0
void ArrayElementExpression::outputCPPImpl(CodeGenerator &cg,
                                           AnalysisResultPtr ar) {
  if (m_global) {
    if (!m_globalName.empty()) {
      VariableTablePtr variables = ar->getScope()->getVariables();
      string name = variables->getGlobalVariableName(cg, ar, m_globalName);
      cg_printf("g->%s", name.c_str());
    } else {
      cg_printf("get_variable_table()->get(");
      m_offset->outputCPP(cg, ar);
      cg_printf(")");
    }
  } else {
    TypePtr type = m_variable->getActualType();
    if (hasContext(UnsetContext)) {
      cg_printf("unsetLval(");
      m_variable->outputCPP(cg, ar);
      cg_printf(", ");
    } else {
      if (m_variable->is(Expression::KindOfScalarExpression) ||
          (type && (type->isInteger() ||
                    type->is(Type::KindOfDouble) ||
                    type->is(Type::KindOfObject) ||
                    type->is(Type::KindOfBoolean)))) {
        cg_printf(type && type->is(Type::KindOfString) ? "((String)" :
                  "((Variant)");
        m_variable->outputCPP(cg, ar);
        cg_printf(")");
      } else {
        m_variable->outputCPP(cg, ar);
      }
    }
    if (m_offset) {
      bool lvalAt = false;
      bool rvalAt = false;
      if (hasContext(UnsetContext)) {
        // do nothing
      } else if (m_context & InvokeArgument) {
        cg_printf(".refvalAt(");
      } else if (m_context & (LValue|RefValue)) {
        cg_printf(".lvalAt(");
        lvalAt = true;
      } else {
        cg_printf(".rvalAt(");
        rvalAt = true;
      }
      m_offset->outputCPP(cg, ar);
      if (!type || !type->is(Type::KindOfString)) {
        bool prehashed = false;
        ScalarExpressionPtr sc =
          dynamic_pointer_cast<ScalarExpression>(m_offset);
        if (sc) {
          int64 hash = sc->getHash();
          if (hash >= 0) {
            cg_printf(", 0x%016llXLL", hash);
            prehashed = true;
          }
        }
        if (!prehashed) {
          cg_printf(", -1");
        }
        if (rvalAt) {
          if (!hasContext(ExistContext)) {
            cg_printf(", true"); // raise undefined index error
          } else {
            cg_printf(", false");
          }
        } else if (lvalAt) {
          if (hasContext(ObjectContext)) {
            // object target might not trigger an array copy
            cg_printf(", true");
          } else {
            cg_printf(", false");
          }
        }
        if (!hasContext(UnsetContext) && sc && sc->isLiteralString()) {
          String s(sc->getLiteralString());
          int64 n;
          if (!s.get()->isStrictlyInteger(n)) {
            cg_printf(", true"); // skip toKey() at run time
          }
        }
      }
      cg_printf(")");
    } else {
      cg_printf(".lvalAt()");
    }
  }
}
コード例 #21
0
ExpressionPtr SimpleFunctionCall::preOptimize(AnalysisResultPtr ar) {
  ar->preOptimize(m_nameExp);
  ar->preOptimize(m_params);
  if (ar->getPhase() != AnalysisResult::SecondPreOptimize) {
    return ExpressionPtr();
  }
  // optimize away various "exists" functions, this may trigger
  // dead code elimination and improve type-inference.
  if (m_className.empty() &&
      (m_type == DefinedFunction ||
       m_type == FunctionExistsFunction ||
       m_type == ClassExistsFunction ||
       m_type == InterfaceExistsFunction) &&
      m_params && m_params->getCount() == 1) {
    ExpressionPtr value = (*m_params)[0];
    if (value->isScalar()) {
      ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>(value);
      if (name && name->isLiteralString()) {
        string symbol = name->getLiteralString();
        switch (m_type) {
        case DefinedFunction: {
          ConstantTablePtr constants = ar->getConstants();
          // system constant
          if (constants->isPresent(symbol)) {
            return CONSTANT("true");
          }
          // user constant
          BlockScopePtr block = ar->findConstantDeclarer(symbol);
          // not found (i.e., undefined)
          if (!block) {
            if (symbol.find("::") == std::string::npos) {
              return CONSTANT("false");
            } else {
              // e.g., defined("self::ZERO")
              return ExpressionPtr();
            }
          }
          constants = block->getConstants();
          // already set to be dynamic
          if (constants->isDynamic(symbol)) return ExpressionPtr();
          ConstructPtr decl = constants->getValue(symbol);
          ExpressionPtr constValue = dynamic_pointer_cast<Expression>(decl);
          if (constValue->isScalar()) {
            return CONSTANT("true");
          } else {
            return ExpressionPtr();
          }
          break;
        }
        case FunctionExistsFunction: {
          const std::string &lname = Util::toLower(symbol);
          if (Option::DynamicInvokeFunctions.find(lname) ==
              Option::DynamicInvokeFunctions.end()) {
            FunctionScopePtr func = ar->findFunction(lname);
            if (!func) {
              return CONSTANT("false");
            } else if (!func->isVolatile()) {
              return CONSTANT("true");
            }
          }
          break;
        }
        case InterfaceExistsFunction: {
          ClassScopePtr cls = ar->findClass(Util::toLower(symbol));
          if (!cls || !cls->isInterface()) {
            return CONSTANT("false");
          } else if (!cls->isVolatile()) {
            return CONSTANT("true");
          }
          break;
        }
        case ClassExistsFunction: {
          ClassScopePtr cls = ar->findClass(Util::toLower(symbol));
          if (!cls || cls->isInterface()) {
            return CONSTANT("false");
          } else if (!cls->isVolatile()) {
            return CONSTANT("true");
          }
          break;
        }
        default:
          ASSERT(false);
        }
      }
    }
  }
  return ExpressionPtr();
}