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

/hphp/compiler/expression/scalar_expression.cpp

https://bitbucket.org/gnanakeethan/hiphop-php
C++ | 526 lines | 452 code | 49 blank | 25 comment | 101 complexity | 513a644d2bd7eddd73e609a4b8415c63 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  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 "hphp/compiler/expression/scalar_expression.h"
  17. #include "hphp/util/parser/hphp.tab.hpp"
  18. #include "hphp/util/util.h"
  19. #include "hphp/compiler/analysis/code_error.h"
  20. #include "hphp/compiler/analysis/block_scope.h"
  21. #include "hphp/compiler/analysis/variable_table.h"
  22. #include "hphp/compiler/analysis/constant_table.h"
  23. #include "hphp/compiler/statement/statement_list.h"
  24. #include "hphp/compiler/analysis/function_scope.h"
  25. #include "hphp/compiler/analysis/class_scope.h"
  26. #include "hphp/compiler/parser/parser.h"
  27. #include "hphp/util/hash.h"
  28. #include "hphp/runtime/base/string_data.h"
  29. #include "hphp/runtime/base/type_conversions.h"
  30. #include "hphp/runtime/base/builtin_functions.h"
  31. #include "hphp/runtime/ext/ext_variable.h"
  32. #include "hphp/compiler/analysis/file_scope.h"
  33. #include <sstream>
  34. #include <cmath>
  35. #include <limits.h>
  36. using namespace HPHP;
  37. ///////////////////////////////////////////////////////////////////////////////
  38. // constructors/destructors
  39. ScalarExpression::ScalarExpression
  40. (EXPRESSION_CONSTRUCTOR_PARAMETERS,
  41. int type, const std::string &value, bool quoted /* = false */)
  42. : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ScalarExpression)),
  43. m_type(type), m_value(value), m_originalValue(value), m_quoted(quoted) {
  44. }
  45. ScalarExpression::ScalarExpression
  46. (EXPRESSION_CONSTRUCTOR_PARAMETERS,
  47. int type, const std::string &value, const std::string &translated,
  48. bool quoted /* false */)
  49. : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ScalarExpression)),
  50. m_type(type), m_value(value), m_originalValue(value),
  51. m_translated(translated) {
  52. }
  53. ScalarExpression::ScalarExpression
  54. (EXPRESSION_CONSTRUCTOR_PARAMETERS,
  55. CVarRef value, bool quoted /* = true */)
  56. : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ScalarExpression)),
  57. m_quoted(quoted) {
  58. if (!value.isNull()) {
  59. String serialized = f_serialize(value);
  60. m_serializedValue = string(serialized.data(), serialized.size());
  61. if (value.isDouble()) {
  62. m_dval = value.toDouble();
  63. }
  64. }
  65. switch (value.getType()) {
  66. case KindOfStaticString:
  67. case KindOfString:
  68. m_type = T_STRING;
  69. break;
  70. case KindOfInt64:
  71. m_type = T_LNUMBER;
  72. break;
  73. case KindOfDouble:
  74. m_type = T_DNUMBER;
  75. break;
  76. default:
  77. assert(false);
  78. }
  79. CStrRef s = value.toString();
  80. m_value = string(s->data(), s->size());
  81. if (m_type == T_DNUMBER && m_value.find_first_of(".eE", 0) == string::npos) {
  82. m_value += ".";
  83. }
  84. m_originalValue = m_value;
  85. }
  86. ExpressionPtr ScalarExpression::clone() {
  87. ScalarExpressionPtr exp(new ScalarExpression(*this));
  88. Expression::deepCopy(exp);
  89. return exp;
  90. }
  91. void ScalarExpression::appendEncapString(const std::string &value) {
  92. m_value += value;
  93. }
  94. void ScalarExpression::toLower(bool funcCall /* = false */) {
  95. assert(funcCall || !m_quoted);
  96. m_value = Util::toLower(m_value);
  97. }
  98. ///////////////////////////////////////////////////////////////////////////////
  99. // static analysis functions
  100. bool ScalarExpression::needsTranslation() const {
  101. switch (m_type) {
  102. case T_LINE:
  103. case T_NS_C:
  104. case T_CLASS_C:
  105. case T_METHOD_C:
  106. case T_FUNC_C:
  107. return true;
  108. default:
  109. return false;
  110. }
  111. }
  112. void ScalarExpression::analyzeProgram(AnalysisResultPtr ar) {
  113. if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
  114. string id = Util::toLower(getIdentifier());
  115. switch (m_type) {
  116. case T_LINE:
  117. if (getLocation()) {
  118. m_translated = lexical_cast<string>(getLocation()->line1);
  119. } else {
  120. m_translated = "0";
  121. }
  122. break;
  123. case T_NS_C:
  124. m_translated = m_value;
  125. break;
  126. // case T_TRAIT_C: Note: T_TRAIT_C is translated at parse time
  127. case T_CLASS_C:
  128. case T_METHOD_C: {
  129. if (!m_translated.empty()) break;
  130. BlockScopeRawPtr b = getScope();
  131. while (b && b->is(BlockScope::FunctionScope)) {
  132. b = b->getOuterScope();
  133. }
  134. m_translated.clear();
  135. if (b && b->is(BlockScope::ClassScope)) {
  136. ClassScopePtr clsScope = dynamic_pointer_cast<ClassScope>(b);
  137. if (!clsScope->isTrait()) {
  138. m_translated = clsScope->getOriginalName();
  139. }
  140. }
  141. if (m_type == T_METHOD_C) {
  142. if (FunctionScopePtr func = getFunctionScope()) {
  143. if (b && b->is(BlockScope::ClassScope)) {
  144. m_translated += "::";
  145. }
  146. if (func->isClosure()) {
  147. m_translated += "{closure}";
  148. } else {
  149. m_translated += func->getOriginalName();
  150. }
  151. }
  152. }
  153. break;
  154. }
  155. case T_FUNC_C:
  156. if (FunctionScopePtr func = getFunctionScope()) {
  157. if (func->isClosure()) {
  158. m_translated = "{closure}";
  159. } else {
  160. m_translated = func->getOriginalName();
  161. }
  162. }
  163. break;
  164. default:
  165. break;
  166. }
  167. }
  168. }
  169. unsigned ScalarExpression::getCanonHash() const {
  170. int64_t val = getHash();
  171. if (val == -1) {
  172. val = hash_string(m_value.c_str(), m_value.size());
  173. }
  174. return unsigned(val) ^ unsigned(val >> 32);
  175. }
  176. bool ScalarExpression::canonCompare(ExpressionPtr e) const {
  177. if (!Expression::canonCompare(e)) return false;
  178. ScalarExpressionPtr s =
  179. static_pointer_cast<ScalarExpression>(e);
  180. return
  181. m_value == s->m_value &&
  182. m_type == s->m_type &&
  183. m_quoted == s->m_quoted;
  184. }
  185. ExpressionPtr ScalarExpression::postOptimize(AnalysisResultConstPtr ar) {
  186. if (!m_expectedType || Type::SameType(m_actualType, m_expectedType)) {
  187. return ExpressionPtr();
  188. }
  189. Variant orig = getVariant();
  190. Variant cast;
  191. bool match = false;
  192. switch (m_expectedType->getKindOf()) {
  193. case Type::KindOfBoolean: match = true; cast = orig.toBoolean(); break;
  194. case Type::KindOfInt64: match = true; cast = orig.toInt64(); break;
  195. case Type::KindOfDouble: match = true; cast = orig.toDouble(); break;
  196. case Type::KindOfString: match = true; cast = orig.toString(); break;
  197. }
  198. if (!match || same(orig, cast)) {
  199. // no changes need to be made
  200. return ExpressionPtr();
  201. }
  202. ExpressionPtr p = makeScalarExpression(ar, cast);
  203. p->setActualType(m_expectedType);
  204. return p;
  205. }
  206. TypePtr ScalarExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
  207. bool coerce) {
  208. assert(false);
  209. return TypePtr();
  210. }
  211. TypePtr ScalarExpression::inferenceImpl(AnalysisResultConstPtr ar,
  212. TypePtr type, bool coerce) {
  213. TypePtr actualType;
  214. switch (m_type) {
  215. case T_STRING:
  216. actualType = Type::String;
  217. break;
  218. case T_NUM_STRING:
  219. case T_LNUMBER:
  220. actualType = Type::Int64;
  221. break;
  222. case T_DNUMBER:
  223. actualType = Type::Double;
  224. break;
  225. case T_LINE:
  226. case T_COMPILER_HALT_OFFSET:
  227. actualType = Type::Int64;
  228. break;
  229. case T_CONSTANT_ENCAPSED_STRING:
  230. case T_ENCAPSED_AND_WHITESPACE:
  231. case T_TRAIT_C:
  232. case T_CLASS_C:
  233. case T_NS_C:
  234. case T_METHOD_C:
  235. case T_FUNC_C:
  236. actualType = Type::String;
  237. break;
  238. default:
  239. assert(false);
  240. break;
  241. }
  242. return checkTypesImpl(ar, type, actualType, coerce);
  243. }
  244. TypePtr ScalarExpression::inferAndCheck(AnalysisResultPtr ar, TypePtr type,
  245. bool coerce) {
  246. IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope());
  247. resetTypes();
  248. if (!Option::AllDynamic &&
  249. ar->getPhase() == AnalysisResult::FirstInference &&
  250. getScope()->isFirstPass() &&
  251. isLiteralString() && m_value.find(' ') == string::npos) {
  252. setDynamicByIdentifier(ar, m_value);
  253. }
  254. return inferenceImpl(ar, type, coerce);
  255. }
  256. ///////////////////////////////////////////////////////////////////////////////
  257. // code generation functions
  258. bool ScalarExpression::isLiteralInteger() const {
  259. switch (m_type) {
  260. case T_NUM_STRING:
  261. {
  262. char ch = m_value[0];
  263. if ((ch == '0' && m_value.size() == 1) || ('1' <= ch && ch <= '9')) {
  264. // Offset could be treated as a long
  265. return true;
  266. }
  267. }
  268. break;
  269. case T_LNUMBER:
  270. return true;
  271. default:
  272. break;
  273. }
  274. return false;
  275. }
  276. int64_t ScalarExpression::getLiteralInteger() const {
  277. assert(isLiteralInteger());
  278. return strtoll(m_value.c_str(), nullptr, 0);
  279. }
  280. bool ScalarExpression::isLiteralString() const {
  281. switch (m_type) {
  282. case T_STRING:
  283. return m_quoted;
  284. case T_CONSTANT_ENCAPSED_STRING:
  285. case T_ENCAPSED_AND_WHITESPACE:
  286. assert(m_quoted); // fall through
  287. case T_TRAIT_C:
  288. case T_CLASS_C:
  289. case T_NS_C:
  290. case T_METHOD_C:
  291. case T_FUNC_C:
  292. return true;
  293. case T_NUM_STRING:
  294. {
  295. char ch = m_value[0];
  296. if (!((ch == '0' && m_value.size() == 1) || ('1' <= ch && ch <= '9'))) {
  297. // Offset must be treated as a string
  298. return true;
  299. }
  300. }
  301. break;
  302. default:
  303. break;
  304. }
  305. return false;
  306. }
  307. std::string ScalarExpression::getLiteralString() const {
  308. return getLiteralStringImpl(false);
  309. }
  310. std::string ScalarExpression::getOriginalLiteralString() const {
  311. return getLiteralStringImpl(true);
  312. }
  313. std::string ScalarExpression::getLiteralStringImpl(bool original) const {
  314. string output;
  315. if (!isLiteralString() && m_type != T_STRING) {
  316. return output;
  317. }
  318. if (m_type == T_CLASS_C || m_type == T_NS_C || m_type == T_METHOD_C ||
  319. m_type == T_FUNC_C || m_type == T_TRAIT_C) {
  320. return m_translated;
  321. }
  322. switch (m_type) {
  323. case T_NUM_STRING:
  324. assert(isLiteralString());
  325. case T_STRING:
  326. case T_ENCAPSED_AND_WHITESPACE:
  327. case T_CONSTANT_ENCAPSED_STRING:
  328. return original ? m_originalValue : m_value;
  329. default:
  330. assert(false);
  331. break;
  332. }
  333. return "";
  334. }
  335. std::string ScalarExpression::getIdentifier() const {
  336. if (isLiteralString()) {
  337. std::string id = getLiteralString();
  338. if (IsIdentifier(id)) {
  339. return id;
  340. }
  341. }
  342. return "";
  343. }
  344. void ScalarExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
  345. switch (m_type) {
  346. case T_CONSTANT_ENCAPSED_STRING:
  347. case T_ENCAPSED_AND_WHITESPACE:
  348. assert(m_quoted); // fall through
  349. case T_STRING:
  350. if (m_quoted) {
  351. string output = Util::escapeStringForPHP(m_originalValue);
  352. cg_printf("%s", output.c_str());
  353. } else {
  354. cg_printf("%s", m_originalValue.c_str());
  355. }
  356. break;
  357. case T_NUM_STRING:
  358. case T_LNUMBER:
  359. case T_DNUMBER:
  360. case T_COMPILER_HALT_OFFSET:
  361. cg_printf("%s", m_originalValue.c_str());
  362. break;
  363. case T_NS_C:
  364. if (cg.translatePredefined()) {
  365. cg_printf("%s", m_translated.c_str());
  366. } else {
  367. cg_printf("__NAMESPACE__");
  368. }
  369. break;
  370. case T_LINE:
  371. case T_TRAIT_C:
  372. case T_CLASS_C:
  373. case T_METHOD_C:
  374. case T_FUNC_C:
  375. if (cg.translatePredefined()) {
  376. cg_printf("%s", m_translated.c_str());
  377. } else {
  378. cg_printf("%s", m_originalValue.c_str());
  379. }
  380. break;
  381. default:
  382. assert(false);
  383. }
  384. }
  385. int64_t ScalarExpression::getHash() const {
  386. int64_t hash = -1;
  387. if (isLiteralInteger()) {
  388. hash = hash_int64(getLiteralInteger());
  389. } else if (isLiteralString()) {
  390. string scs = getLiteralString();
  391. int64_t res;
  392. if (is_strictly_integer(scs.c_str(), scs.size(), res)) {
  393. hash = hash_int64(res);
  394. } else {
  395. hash = hash_string(scs.c_str(), scs.size());
  396. }
  397. }
  398. return hash;
  399. }
  400. Variant ScalarExpression::getVariant() const {
  401. if (!m_serializedValue.empty()) {
  402. Variant ret = unserialize_from_buffer(
  403. m_serializedValue.data(), m_serializedValue.size(), null_array);
  404. if (ret.isDouble()) {
  405. return m_dval;
  406. }
  407. return ret;
  408. }
  409. switch (m_type) {
  410. case T_ENCAPSED_AND_WHITESPACE:
  411. case T_CONSTANT_ENCAPSED_STRING:
  412. case T_STRING:
  413. case T_NUM_STRING:
  414. return String(m_value);
  415. case T_LNUMBER:
  416. case T_COMPILER_HALT_OFFSET:
  417. return strtoll(m_value.c_str(), nullptr, 0);
  418. case T_LINE:
  419. return String(m_translated).toInt64();
  420. case T_TRAIT_C:
  421. case T_CLASS_C:
  422. case T_NS_C:
  423. case T_METHOD_C:
  424. case T_FUNC_C:
  425. return String(m_translated);
  426. case T_DNUMBER:
  427. return String(m_value).toDouble();
  428. default:
  429. assert(false);
  430. }
  431. return uninit_null();
  432. }
  433. bool ScalarExpression::getString(const std::string *&s) const {
  434. switch (m_type) {
  435. case T_ENCAPSED_AND_WHITESPACE:
  436. case T_CONSTANT_ENCAPSED_STRING:
  437. case T_STRING:
  438. case T_NUM_STRING:
  439. s = &m_value;
  440. return true;
  441. case T_TRAIT_C:
  442. case T_CLASS_C:
  443. case T_NS_C:
  444. case T_METHOD_C:
  445. case T_FUNC_C:
  446. s = &m_translated;
  447. return true;
  448. default:
  449. return false;
  450. }
  451. }
  452. bool ScalarExpression::getInt(int64_t &i) const {
  453. if (m_type == T_LNUMBER || m_type == T_COMPILER_HALT_OFFSET) {
  454. i = strtoll(m_value.c_str(), nullptr, 0);
  455. return true;
  456. } else if (m_type == T_LINE) {
  457. i = getLocation() ? getLocation()->line1 : 0;
  458. return true;
  459. }
  460. return false;
  461. }
  462. bool ScalarExpression::getDouble(double &d) const {
  463. if (m_type == T_DNUMBER) {
  464. Variant v = getVariant();
  465. assert(v.isDouble());
  466. d = v.toDouble();
  467. return true;
  468. }
  469. return false;
  470. }
  471. void ScalarExpression::setCompilerHaltOffset(int64_t ofs) {
  472. assert(m_type == T_COMPILER_HALT_OFFSET);
  473. std::ostringstream ss;
  474. ss << ofs;
  475. m_value = ss.str();
  476. m_originalValue = ss.str();
  477. }