PageRenderTime 93ms CodeModel.GetById 37ms RepoModel.GetById 1ms app.codeStats 0ms

/src/runtime/eval/ext/ext.cpp

https://github.com/tmjnaid/hiphop-php
C++ | 297 lines | 248 code | 29 blank | 20 comment | 33 complexity | 78ad951586be19aac8a0463cdf4f3ce0 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/ext/ext.h>
  17. #include <runtime/eval/base/function.h>
  18. #include <runtime/eval/runtime/eval_state.h>
  19. #include <runtime/eval/runtime/variable_environment.h>
  20. #include <runtime/eval/parser/parser.h>
  21. #include <runtime/eval/ast/static_statement.h>
  22. #include <runtime/eval/ast/statement_list_statement.h>
  23. #include <runtime/eval/ast/function_statement.h>
  24. #include <runtime/eval/ast/function_call_expression.h>
  25. #include <runtime/eval/ast/class_statement.h>
  26. #include <runtime/ext/ext_variable.h>
  27. #include <runtime/ext/ext_class.h>
  28. #include <runtime/ext/ext_array.h>
  29. #include <runtime/ext/ext_misc.h>
  30. #include <runtime/ext/ext_error.h>
  31. #include <runtime/ext/ext_options.h>
  32. #include <runtime/ext/ext_function.h>
  33. #include <runtime/ext/ext_reflection.h>
  34. #include <runtime/eval/eval.h>
  35. namespace HPHP {
  36. namespace Eval {
  37. using namespace std;
  38. ///////////////////////////////////////////////////////////////////////////////
  39. class ExtFunction : public Function {
  40. public:
  41. Variant invoke(CArrRef params) const;
  42. Variant directInvoke(VariableEnvironment &env,
  43. const FunctionCallExpression *caller) const;
  44. virtual Variant invokeImpl(VariableEnvironment &env,
  45. CArrRef params) const = 0;
  46. };
  47. Variant ExtFunction::invoke(CArrRef params) const {
  48. throw NotSupportedException("Dynamic invoke of special functions",
  49. "It's hard and I haven't gotten around to it");
  50. }
  51. Variant ExtFunction::directInvoke(VariableEnvironment &env,
  52. const FunctionCallExpression *caller) const {
  53. return invokeImpl(env, caller->getParams(env));
  54. }
  55. #define EVAL_EXT(name) \
  56. class Eval##name : public ExtFunction { \
  57. public: \
  58. Variant invokeImpl(VariableEnvironment &env, \
  59. CArrRef params) const; \
  60. }
  61. #define EVAL_EXT_DYN(name) \
  62. class Eval##name : public ExtFunction { \
  63. public: \
  64. Variant invokeImpl(VariableEnvironment &env, \
  65. CArrRef params) const { \
  66. return invoke(params); \
  67. } \
  68. Variant invoke(CArrRef params) const; \
  69. }
  70. EVAL_EXT(Extract);
  71. EVAL_EXT(Define);
  72. EVAL_EXT(FuncGetArg);
  73. EVAL_EXT(FuncGetArgs);
  74. EVAL_EXT(FuncNumArgs);
  75. EVAL_EXT(Compact);
  76. EVAL_EXT(CreateFunction);
  77. EVAL_EXT(Assert);
  78. EVAL_EXT(GetDefinedVars);
  79. EVAL_EXT_DYN(HphpGetClassInfo);
  80. EVAL_EXT_DYN(ClassExists);
  81. EVAL_EXT_DYN(InterfaceExists);
  82. #undef EVAL_EXT
  83. class EvalFunctionExists : public ExtFunction {
  84. public:
  85. EvalFunctionExists();
  86. Variant invokeImpl(VariableEnvironment &env,
  87. CArrRef params) const;
  88. private:
  89. hphp_const_char_imap<bool> m_blacklist;
  90. };
  91. EvalOverrides::EvalOverrides() {
  92. m_functions["extract"] = new EvalExtract();
  93. m_functions["define"] = new EvalDefine();
  94. m_functions["func_get_arg"] = new EvalFuncGetArg();
  95. m_functions["func_get_args"] = new EvalFuncGetArgs();
  96. m_functions["func_num_args"] = new EvalFuncNumArgs();
  97. m_functions["compact"] = new EvalCompact();
  98. m_functions["create_function"] = new EvalCreateFunction();
  99. m_functions["assert"] = new EvalAssert();
  100. m_functions["function_exists"] = new EvalFunctionExists();
  101. m_functions["class_exists"] = new EvalClassExists();
  102. m_functions["interface_exists"] = new EvalInterfaceExists();
  103. m_functions["get_defined_vars"] = new EvalGetDefinedVars();
  104. m_functions["hphp_get_class_info"] = new EvalHphpGetClassInfo();
  105. }
  106. EvalOverrides::~EvalOverrides() {
  107. for (hphp_const_char_imap<const Function*>::iterator it =
  108. m_functions.begin(); it != m_functions.end(); ++it) {
  109. delete it->second;
  110. }
  111. m_functions.clear();
  112. }
  113. const Function *EvalOverrides::findFunction(const char *name) const {
  114. hphp_const_char_imap<const Function*>::const_iterator it =
  115. m_functions.find(name);
  116. if (it != m_functions.end()) {
  117. return it->second;
  118. }
  119. return NULL;
  120. }
  121. EvalOverrides evalOverrides;
  122. //////////////////////////////////////////////////////////////////////////////
  123. ///// Invoke definitions
  124. Variant EvalExtract::invokeImpl(VariableEnvironment &env,
  125. CArrRef params) const {
  126. int size = params.size();
  127. switch (size) {
  128. case 1: return extract(&env,params.rvalAt(0));
  129. case 2: return extract(&env,params.rvalAt(0), params.rvalAt(1));
  130. case 3: return extract(&env,params.rvalAt(0), params.rvalAt(1),
  131. params.rvalAt(2));
  132. default: throw InvalidFunctionCallException("extract");
  133. }
  134. }
  135. Variant EvalDefine::invokeImpl(VariableEnvironment &env,
  136. CArrRef params) const {
  137. int size = params.size();
  138. switch (size) {
  139. case 2:
  140. case 3:
  141. {
  142. Variant n = params.rvalAt(0);
  143. if (!f_defined(n)) {
  144. return RequestEvalState::declareConstant(n, params.rvalAt(1));
  145. } else {
  146. raise_notice("Constant %s already defined", n.toString().data());
  147. return false;
  148. }
  149. }
  150. default: throw InvalidFunctionCallException("define");
  151. }
  152. }
  153. Variant EvalFuncGetArg::invokeImpl(VariableEnvironment &env,
  154. CArrRef params) const {
  155. int size = params.size();
  156. switch (size) {
  157. case 1: return env.getParams().rvalAt(params.rvalAt(0));
  158. default: throw InvalidFunctionCallException("func_get_arg");
  159. }
  160. }
  161. Variant EvalFuncGetArgs::invokeImpl(VariableEnvironment &env,
  162. CArrRef params) const {
  163. int size = params.size();
  164. switch (size) {
  165. case 0: {
  166. Array res = Array::Create();
  167. for (ArrayIter iter(env.getParams()); !iter.end(); iter.next()) {
  168. res.append(iter.second());
  169. }
  170. return res;
  171. }
  172. default: throw InvalidFunctionCallException("func_get_args");
  173. }
  174. }
  175. Variant EvalFuncNumArgs::invokeImpl(VariableEnvironment &env,
  176. CArrRef params) const {
  177. int size = params.size();
  178. if (size != 0) throw InvalidFunctionCallException("func_num_args");
  179. return env.getParams().size();
  180. }
  181. Variant EvalCompact::invokeImpl(VariableEnvironment &env,
  182. CArrRef params) const {
  183. int size = params.size();
  184. if (size == 0) throw InvalidFunctionCallException("compact");
  185. return compact(&env, params.size(), params.rvalAt(0),
  186. params.slice(1, params.size() - 1, false));
  187. }
  188. Variant EvalCreateFunction::invokeImpl(VariableEnvironment &env,
  189. CArrRef params) const {
  190. int size = params.size();
  191. if (size != 2) throw InvalidFunctionCallException("create_function");
  192. Variant var = params.rvalAt(0);
  193. Variant body = params.rvalAt(1);
  194. vector<StaticStatementPtr> statics;
  195. ostringstream fnStream;
  196. int64 id = RequestEvalState::unique();
  197. fnStream << "<?php function lambda_" << id << "(" << var.toString().data() <<
  198. ") {" << body.toString().data() << "}\n";
  199. StatementPtr bodyAst = Parser::parseString(fnStream.str().c_str(), statics);
  200. if (!bodyAst) return false;
  201. ostringstream nameStream;
  202. nameStream << "$lambda_" << id;
  203. FunctionStatementPtr f = bodyAst->cast<StatementListStatement>()->stmts()[0];
  204. ASSERT(f);
  205. f->changeName(nameStream.str());
  206. StringCodeContainer *cc = new StringCodeContainer(bodyAst);
  207. RequestEvalState::addCodeContainer(cc);
  208. f->eval(env);
  209. return String(f->name().c_str(), f->name().size(), AttachLiteral);
  210. }
  211. Variant EvalAssert::invokeImpl(VariableEnvironment &env,
  212. CArrRef params) const {
  213. Variant assertion = params.rvalAt(0);
  214. if (assertion.isString()) {
  215. // Todo: eval this assertion
  216. return null;
  217. }
  218. return f_assert(assertion);
  219. }
  220. Variant EvalClassExists::invoke(CArrRef params) const {
  221. String cname = params.rvalAt(0);
  222. if (!f_class_exists(cname, false)) {
  223. if ((params.size() == 1 || params.rvalAt(1).toBoolean()) &&
  224. !f_interface_exists(cname, false) &&
  225. eval_try_autoload(cname.data())) {
  226. return f_class_exists(cname, false);
  227. }
  228. return false;
  229. }
  230. return true;
  231. }
  232. Variant EvalInterfaceExists::invoke(CArrRef params) const {
  233. String cname = params.rvalAt(0);
  234. if (!f_interface_exists(cname, false)) {
  235. if ((params.size() == 1 || params.rvalAt(1).toBoolean()) &&
  236. !f_class_exists(cname, false) &&
  237. eval_try_autoload(cname.data())) {
  238. return f_interface_exists(cname, false);
  239. }
  240. return false;
  241. }
  242. return true;
  243. }
  244. Variant EvalGetDefinedVars::invokeImpl(VariableEnvironment &env,
  245. CArrRef params) const {
  246. return env.getDefinedVariables();
  247. }
  248. Variant EvalHphpGetClassInfo::invoke(CArrRef params) const {
  249. String cname = params.rvalAt(0);
  250. if (!f_class_exists(cname) && !f_interface_exists(cname)) {
  251. eval_try_autoload(cname.data());
  252. }
  253. return f_hphp_get_class_info(cname);
  254. }
  255. EvalFunctionExists::EvalFunctionExists() {
  256. m_blacklist["fb_get_derived_classes"] = true;
  257. }
  258. Variant EvalFunctionExists::invokeImpl(VariableEnvironment &env,
  259. CArrRef params) const {
  260. if (params.size() != 1)
  261. throw InvalidFunctionCallException("function_exists");
  262. String fn = params.rvalAt(0).toString();
  263. if (m_blacklist.find(fn.data()) != m_blacklist.end()) return false;
  264. return f_function_exists(fn);
  265. }
  266. ///////////////////////////////////////////////////////////////////////////////
  267. }
  268. }