PageRenderTime 27ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/src/compiler/expression/parameter_expression.cpp

https://github.com/kevlund/hiphop-php
C++ | 309 lines | 242 code | 32 blank | 35 comment | 88 complexity | 3ca39a3c25deb62158795855a19300f8 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include <compiler/expression/parameter_expression.h>
  17. #include <compiler/analysis/function_scope.h>
  18. #include <compiler/analysis/file_scope.h>
  19. #include <compiler/analysis/variable_table.h>
  20. #include <compiler/analysis/class_scope.h>
  21. #include <compiler/analysis/code_error.h>
  22. #include <util/util.h>
  23. #include <compiler/option.h>
  24. #include <compiler/expression/constant_expression.h>
  25. using namespace HPHP;
  26. using namespace std;
  27. using namespace boost;
  28. ///////////////////////////////////////////////////////////////////////////////
  29. // constructors/destructors
  30. ParameterExpression::ParameterExpression
  31. (EXPRESSION_CONSTRUCTOR_PARAMETERS,
  32. const std::string &type, const std::string &name, bool ref,
  33. ExpressionPtr defaultValue)
  34. : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ParameterExpression)),
  35. m_originalType(type), m_name(name), m_ref(ref), m_hasRTTI(false),
  36. m_defaultValue(defaultValue) {
  37. m_type = Util::toLower(type);
  38. if (m_defaultValue) {
  39. m_defaultValue->setContext(InParameterExpression);
  40. }
  41. }
  42. ExpressionPtr ParameterExpression::clone() {
  43. ParameterExpressionPtr exp(new ParameterExpression(*this));
  44. Expression::deepCopy(exp);
  45. exp->m_defaultValue = Clone(m_defaultValue);
  46. return exp;
  47. }
  48. ///////////////////////////////////////////////////////////////////////////////
  49. // parser functions
  50. void ParameterExpression::parseHandler(ClassScopePtr cls) {
  51. if (!m_type.empty()) {
  52. if (m_type == "self") {
  53. m_type = cls->getName();
  54. } else if (m_type == "parent") {
  55. if (!cls->getParent().empty()) {
  56. m_type = cls->getParent();
  57. }
  58. }
  59. }
  60. }
  61. void ParameterExpression::defaultToNull(AnalysisResultPtr ar) {
  62. ASSERT(!m_defaultValue);
  63. m_defaultValue = CONSTANT("null");
  64. }
  65. ///////////////////////////////////////////////////////////////////////////////
  66. // static analysis functions
  67. void ParameterExpression::analyzeProgram(AnalysisResultPtr ar) {
  68. if (m_defaultValue) m_defaultValue->analyzeProgram(ar);
  69. if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
  70. if (!m_type.empty()) {
  71. addUserClass(ar, m_type);
  72. }
  73. // Have to use non const ref params for magic methods
  74. FunctionScopePtr fs = getFunctionScope();
  75. if (fs->isMagicMethod() || fs->getName() == "offsetget") {
  76. fs->getVariables()->addLvalParam(m_name);
  77. }
  78. if (m_ref) fs->setNeedsCheckMem();
  79. }
  80. }
  81. ConstructPtr ParameterExpression::getNthKid(int n) const {
  82. switch (n) {
  83. case 0:
  84. return m_defaultValue;
  85. default:
  86. ASSERT(false);
  87. break;
  88. }
  89. return ConstructPtr();
  90. }
  91. int ParameterExpression::getKidCount() const {
  92. return 1;
  93. }
  94. void ParameterExpression::setNthKid(int n, ConstructPtr cp) {
  95. switch (n) {
  96. case 0:
  97. m_defaultValue = boost::dynamic_pointer_cast<Expression>(cp);
  98. break;
  99. default:
  100. break;
  101. }
  102. }
  103. TypePtr ParameterExpression::getTypeSpecForClass(AnalysisResultPtr ar,
  104. bool forInference) {
  105. TypePtr ret;
  106. if (forInference) {
  107. ClassScopePtr cls = ar->findClass(m_type);
  108. if (Option::SystemGen ||
  109. !cls || cls->isRedeclaring() || cls->derivedByDynamic()) {
  110. if (!cls && getScope()->isFirstPass()) {
  111. ConstructPtr self = shared_from_this();
  112. Compiler::Error(Compiler::UnknownClass, self);
  113. }
  114. ret = Type::Variant;
  115. }
  116. }
  117. if (!ret) {
  118. ret = Type::CreateObjectType(m_type);
  119. }
  120. assert(ret);
  121. return ret;
  122. }
  123. TypePtr ParameterExpression::getTypeSpec(AnalysisResultPtr ar,
  124. bool forInference) {
  125. const Type::TypePtrMap &types = Type::GetTypeHintTypes();
  126. Type::TypePtrMap::const_iterator iter;
  127. TypePtr ret;
  128. if (m_type.empty()) {
  129. ret = Type::Some;
  130. } else if ((iter = types.find(m_type)) != types.end()) {
  131. ret = iter->second;
  132. } else {
  133. ret = getTypeSpecForClass(ar, forInference);
  134. }
  135. ConstantExpressionPtr p;
  136. if (ret->isPrimitive() &&
  137. m_defaultValue &&
  138. (p = dynamic_pointer_cast<ConstantExpression>(m_defaultValue)) &&
  139. p->isNull()) {
  140. // if we have a primitive type on the LHS w/ a default
  141. // of null, then don't bother to infer it's type, since we will
  142. // not specialize for this case
  143. ret = Type::Some;
  144. }
  145. // we still want the above to run, so to record errors and infer defaults
  146. if (m_ref && forInference) {
  147. ret = Type::Variant;
  148. }
  149. return ret;
  150. }
  151. TypePtr ParameterExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
  152. bool coerce) {
  153. ASSERT(type->is(Type::KindOfSome) || type->is(Type::KindOfAny));
  154. TypePtr ret = getTypeSpec(ar, true);
  155. VariableTablePtr variables = getScope()->getVariables();
  156. // Functions that can be called dynamically have to have
  157. // variant parameters, even if they have a type hint
  158. if ((Option::AllDynamic || getFunctionScope()->isDynamic()) ||
  159. getFunctionScope()->isRedeclaring() ||
  160. getFunctionScope()->isVirtual()) {
  161. if (!Option::HardTypeHints || !ret->isExactType()) {
  162. variables->forceVariant(ar, m_name, VariableTable::AnyVars);
  163. ret = Type::Variant;
  164. }
  165. }
  166. if (m_defaultValue && !m_ref) {
  167. ret = m_defaultValue->inferAndCheck(ar, ret, false);
  168. // TODO: emit compiler error when default value does not
  169. // match the type spec (if we have a type spec)
  170. }
  171. // parameters are like variables, but we need to remember these are
  172. // parameters so when variable table is generated, they are not generated
  173. // as declared variables.
  174. return variables->addParamLike(m_name, ret, ar, shared_from_this(),
  175. getScope()->isFirstPass());
  176. }
  177. ///////////////////////////////////////////////////////////////////////////////
  178. // code generation functions
  179. void ParameterExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
  180. if (!m_type.empty()) cg_printf("%s ", m_originalType.c_str());
  181. if (m_ref) cg_printf("&");
  182. cg_printf("$%s", m_name.c_str());
  183. if (m_defaultValue) {
  184. cg_printf(" = ");
  185. m_defaultValue->outputPHP(cg, ar);
  186. }
  187. }
  188. void ParameterExpression::outputCPPImpl(CodeGenerator &cg,
  189. AnalysisResultPtr ar) {
  190. FunctionScopePtr func = getFunctionScope();
  191. VariableTablePtr variables = func->getVariables();
  192. Symbol *sym = variables->getSymbol(m_name);
  193. assert(sym && sym->isParameter());
  194. CodeGenerator::Context context = cg.getContext();
  195. bool typedWrapper = (context == CodeGenerator::CppTypedParamsWrapperImpl ||
  196. context == CodeGenerator::CppTypedParamsWrapperDecl);
  197. TypePtr paramType =
  198. typedWrapper && func->getParamTypeSpec(sym->getParameterIndex()) ?
  199. Type::Variant : func->getParamType(sym->getParameterIndex());
  200. bool wrapper = typedWrapper ||
  201. context == CodeGenerator::CppFunctionWrapperImpl ||
  202. context == CodeGenerator::CppFunctionWrapperDecl;
  203. bool isCVarRef = false;
  204. const char *prefix = "";
  205. if (m_ref) {
  206. cg_printf("VRefParam");
  207. if (!wrapper) {
  208. prefix = "r";
  209. }
  210. } else if (wrapper ||
  211. (!variables->isLvalParam(m_name) &&
  212. !variables->getAttribute(VariableTable::ContainsDynamicVariable) &&
  213. !variables->getAttribute(VariableTable::ContainsExtract))) {
  214. if (paramType->is(Type::KindOfVariant) ||
  215. paramType->is(Type::KindOfSome)) {
  216. cg_printf("CVarRef");
  217. isCVarRef = true;
  218. }
  219. else if (paramType->is(Type::KindOfArray)) cg_printf("CArrRef");
  220. else if (paramType->is(Type::KindOfString)) cg_printf("CStrRef");
  221. else paramType->outputCPPDecl(cg, ar, getScope());
  222. } else {
  223. paramType->outputCPPDecl(cg, ar, getScope());
  224. }
  225. cg_printf(" %s%s%s",
  226. prefix, Option::VariablePrefix,
  227. CodeGenerator::FormatLabel(m_name).c_str());
  228. if (m_defaultValue && sym->getParameterIndex() >= func->getMinParamCount()) {
  229. bool comment = context == CodeGenerator::CppTypedParamsWrapperImpl ||
  230. context == CodeGenerator::CppFunctionWrapperImpl ||
  231. context == CodeGenerator::CppImplementation ||
  232. (context == CodeGenerator::CppDeclaration && func->isInlined());
  233. if (comment) {
  234. cg_printf(" // ");
  235. }
  236. cg_printf(" = ");
  237. ConstantExpressionPtr con =
  238. dynamic_pointer_cast<ConstantExpression>(m_defaultValue);
  239. bool done = false;
  240. if (con && con->isNull()) {
  241. done = true;
  242. if (isCVarRef) {
  243. cg_printf("null_variant");
  244. } else if (paramType->is(Type::KindOfVariant) ||
  245. paramType->is(Type::KindOfSome)) {
  246. cg_printf("null");
  247. } else if (paramType->is(Type::KindOfObject)) {
  248. cg_printf("Object()");
  249. } else if (paramType->is(Type::KindOfArray)) {
  250. cg_printf("Array()");
  251. } else if (paramType->is(Type::KindOfString)) {
  252. cg_printf("String()");
  253. } else {
  254. done = false;
  255. }
  256. }
  257. if (!done) {
  258. if (comment) {
  259. cg.setContext(CodeGenerator::CppParameterDefaultValueImpl);
  260. } else {
  261. cg.setContext(CodeGenerator::CppParameterDefaultValueDecl);
  262. }
  263. bool isScalar = m_defaultValue->isScalar();
  264. if (isCVarRef && isScalar) {
  265. ASSERT(!cg.hasScalarVariant());
  266. cg.setScalarVariant();
  267. }
  268. m_defaultValue->outputCPP(cg, ar);
  269. if (isCVarRef && isScalar) cg.clearScalarVariant();
  270. ASSERT(!cg.hasScalarVariant());
  271. cg.setContext(context);
  272. }
  273. if (comment) {
  274. cg_printf("\n");
  275. }
  276. }
  277. }