PageRenderTime 47ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/src/runtime/eval/ast/method_statement.cpp

https://github.com/ckwalsh/hiphop-php
C++ | 242 lines | 201 code | 21 blank | 20 comment | 49 complexity | 14cb81c6b44eec91655a9c686f986f52 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 <runtime/eval/ast/method_statement.h>
  17. #include <runtime/eval/ast/statement_list_statement.h>
  18. #include <runtime/eval/runtime/variable_environment.h>
  19. #include <runtime/eval/ast/class_statement.h>
  20. #include <runtime/eval/runtime/eval_state.h>
  21. #include <runtime/eval/ast/function_call_expression.h>
  22. namespace HPHP {
  23. namespace Eval {
  24. using namespace std;
  25. ///////////////////////////////////////////////////////////////////////////////
  26. MethodStatement::MethodStatement(STATEMENT_ARGS, const string &name,
  27. const ClassStatement *cls, int modifiers,
  28. const string &doc)
  29. : FunctionStatement(STATEMENT_PASS, name, doc), m_class(cls),
  30. m_modifiers(modifiers),
  31. m_fullName(string(cls->name().c_str()) + "::" + name) {
  32. if ((m_modifiers & (ClassStatement::Public | ClassStatement::Protected |
  33. ClassStatement::Private)) == 0) {
  34. m_modifiers |= ClassStatement::Public;
  35. }
  36. m_callInfo.m_invoker = (void*)MethInvoker;
  37. m_callInfo.m_invokerFewArgs = (void*)MethInvokerFewArgs;
  38. if (m_modifiers & ClassStatement::Static) {
  39. m_callInfo.m_flags |= CallInfo::StaticMethod;
  40. } else {
  41. m_callInfo.m_flags |= CallInfo::Method;
  42. }
  43. }
  44. String MethodStatement::fullName() const {
  45. return m_fullName;
  46. }
  47. void MethodStatement::eval(VariableEnvironment &env) const {
  48. if (env.isGotoing()) return;
  49. ENTER_STMT;
  50. // register with reflection, invoke, etc.
  51. }
  52. LVariableTable *MethodStatement::getStaticVars(VariableEnvironment &env)
  53. const {
  54. return &RequestEvalState::getMethodStatics(this, env.currentClass());
  55. }
  56. Variant MethodStatement::invokeInstance(CObjRef obj, CArrRef params,
  57. bool check /* = true */) const {
  58. if (getModifiers() & ClassStatement::Static) {
  59. return invokeStatic(obj->o_getClassName(), params);
  60. }
  61. if (check) attemptAccess(FrameInjection::GetClassName(false));
  62. // The debug frame should have been pushed at ObjectMethodExpression
  63. DECLARE_THREAD_INFO_NOINIT
  64. MethScopeVariableEnvironment env(this, params.size());
  65. env.setCurrentObject(obj);
  66. String clsName(m_class->name().c_str(), m_class->name().size(),
  67. AttachLiteral);
  68. EvalFrameInjection fi(clsName, m_fullName.c_str(), env,
  69. loc()->file, obj.get());
  70. if (m_ref) {
  71. return ref(invokeImpl(env, params));
  72. }
  73. return invokeImpl(env, params);
  74. }
  75. Variant MethodStatement::
  76. invokeInstanceDirect(CObjRef obj, VariableEnvironment &env,
  77. const FunctionCallExpression *caller) const {
  78. if (getModifiers() & ClassStatement::Static) {
  79. return invokeStaticDirect(obj->o_getClassName(), env, caller);
  80. }
  81. attemptAccess(FrameInjection::GetClassName(false));
  82. DECLARE_THREAD_INFO_NOINIT
  83. MethScopeVariableEnvironment fenv(this, 0);
  84. directBind(env, caller, fenv);
  85. fenv.setCurrentObject(obj);
  86. String clsName(m_class->name().c_str(), m_class->name().size(),
  87. AttachLiteral);
  88. EvalFrameInjection fi(clsName, m_fullName.c_str(), fenv,
  89. loc()->file, obj.get());
  90. if (m_ref) {
  91. return ref(evalBody(fenv));
  92. }
  93. return evalBody(fenv);
  94. }
  95. Variant MethodStatement::invokeStatic(const char* cls, CArrRef params,
  96. bool check /* = true */) const {
  97. if (check) attemptAccess(FrameInjection::GetClassName(false));
  98. DECLARE_THREAD_INFO_NOINIT
  99. MethScopeVariableEnvironment env(this, params.size());
  100. env.setCurrentClass(cls);
  101. String clsName(m_class->name().c_str(), m_class->name().size(),
  102. AttachLiteral);
  103. EvalFrameInjection fi(clsName, m_fullName.c_str(), env, loc()->file);
  104. if (m_ref) {
  105. return ref(invokeImpl(env, params));
  106. }
  107. return invokeImpl(env, params);
  108. }
  109. Variant MethodStatement::
  110. invokeStaticDirect(const char* cls, VariableEnvironment &env,
  111. const FunctionCallExpression *caller)
  112. const {
  113. attemptAccess(FrameInjection::GetClassName(false));
  114. MethScopeVariableEnvironment fenv(this, 0);
  115. directBind(env, caller, fenv);
  116. fenv.setCurrentClass(cls);
  117. DECLARE_THREAD_INFO_NOINIT
  118. String clsName(m_class->name().c_str(), m_class->name().size(),
  119. AttachLiteral);
  120. EvalFrameInjection fi(clsName, m_fullName.c_str(), fenv,
  121. loc()->file);
  122. if (m_ref) {
  123. return ref(evalBody(fenv));
  124. }
  125. return evalBody(fenv);
  126. }
  127. Variant MethodStatement::evalBody(VariableEnvironment &env) const {
  128. if (isAbstract()) {
  129. raise_error("Cannot call abstract method %s()", m_fullName.c_str());
  130. }
  131. if (m_ref) {
  132. return ref(FunctionStatement::evalBody(env));
  133. } else {
  134. return FunctionStatement::evalBody(env);
  135. }
  136. }
  137. void MethodStatement::getInfo(ClassInfo::MethodInfo &info) const {
  138. FunctionStatement::getInfo(info);
  139. int attr = info.attribute == ClassInfo::IsNothing ? 0 : info.attribute;
  140. if (m_modifiers & ClassStatement::Abstract) attr |= ClassInfo::IsAbstract;
  141. if (m_modifiers & ClassStatement::Final) attr |= ClassInfo::IsFinal;
  142. if (m_modifiers & ClassStatement::Protected) attr |= ClassInfo::IsProtected;
  143. if (m_modifiers & ClassStatement::Private) attr |= ClassInfo::IsPrivate;
  144. if (m_modifiers & ClassStatement::Static) attr |= ClassInfo::IsStatic;
  145. if (!(attr & ClassInfo::IsProtected || attr & ClassInfo::IsPrivate)) {
  146. attr |= ClassInfo::IsPublic;
  147. }
  148. info.attribute = (ClassInfo::Attribute)attr;
  149. }
  150. void MethodStatement::attemptAccess(const char *context) const {
  151. int mods = getModifiers();
  152. const ClassStatement *cs = getClass();
  153. ClassStatement::Modifier level = ClassStatement::Public;
  154. if (mods & ClassStatement::Private) level = ClassStatement::Private;
  155. else if (mods & ClassStatement::Protected) level = ClassStatement::Protected;
  156. bool access = true;
  157. if (level == ClassStatement::Protected) {
  158. while (!cs->hasAccess(context, level)) {
  159. while ((cs = cs->parentStatement())) {
  160. if (cs->findMethod(m_name.c_str())) {
  161. break;
  162. }
  163. }
  164. if (!cs) {
  165. access = false;
  166. break;
  167. }
  168. }
  169. } else {
  170. access = cs->hasAccess(context, level);
  171. }
  172. // special case when handling parent's private constructors that are allowed
  173. if (!access) {
  174. if (level == ClassStatement::Private &&
  175. (strcasecmp(m_name.c_str(), "__construct") == 0 ||
  176. strcasecmp(m_name.c_str(), getClass()->name().c_str()) == 0)) {
  177. access = cs->hasAccess(context, ClassStatement::Protected);
  178. }
  179. }
  180. if (!access) {
  181. const char *mod = "protected";
  182. if (level == ClassStatement::Private) mod = "private";
  183. throw FatalErrorException(0, "Attempt to call %s %s::%s()%s%s",
  184. mod, getClass()->name().c_str(), m_name.c_str(),
  185. context[0] ? " from " : "",
  186. context[0] ? context : "");
  187. }
  188. }
  189. bool MethodStatement::isAbstract() const {
  190. return getModifiers() & ClassStatement::Abstract ||
  191. m_class->getModifiers() & ClassStatement::Interface;
  192. }
  193. Variant MethodStatement::MethInvoker(MethodCallPackage &mcp, CArrRef params) {
  194. const MethodStatement *ms = (const MethodStatement*)mcp.extra;
  195. if (ms->getModifiers() & ClassStatement::Static || !mcp.obj) {
  196. String cn(mcp.getClassName());
  197. if (ms->refReturn()) {
  198. return ref(ms->invokeStatic(cn.c_str(), params));
  199. } else {
  200. return ms->invokeStatic(cn.c_str(), params);
  201. }
  202. } else {
  203. if (ms->refReturn()) {
  204. return ref(ms->invokeInstance(mcp.rootObj, params));
  205. } else {
  206. return ms->invokeInstance(mcp.rootObj, params);
  207. }
  208. }
  209. }
  210. Variant MethodStatement::MethInvokerFewArgs(MethodCallPackage &mcp,
  211. int count, INVOKE_FEW_ARGS_IMPL_ARGS) {
  212. return MethInvoker(mcp,
  213. collect_few_args_ref(count, INVOKE_FEW_ARGS_PASS_ARGS));
  214. }
  215. void MethodStatement::dump(std::ostream &out) const {
  216. ClassStatement::dumpModifiers(out, m_modifiers, false);
  217. FunctionStatement::dump(out);
  218. }
  219. ///////////////////////////////////////////////////////////////////////////////
  220. }
  221. }