Aer Interpreter Source
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1263 lines
42 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. /*
  2. * Symisc PH7: An embeddable bytecode compiler and a virtual machine for the PHP(5) programming language.
  3. * Copyright (C) 2011-2012, Symisc Systems http://ph7.symisc.net/
  4. * Version 2.1.4
  5. * For information on licensing,redistribution of this file,and for a DISCLAIMER OF ALL WARRANTIES
  6. * please contact Symisc Systems via:
  7. * legal@symisc.net
  8. * licensing@symisc.net
  9. * contact@symisc.net
  10. * or visit:
  11. * http://ph7.symisc.net/
  12. */
  13. /* $SymiscID: memobj.c v2.7 FreeBSD 2012-08-09 03:40 stable <chm@symisc.net> $ */
  14. #include "ph7int.h"
  15. /* This file handle low-level stuff related to indexed memory objects [i.e: ph7_value] */
  16. /*
  17. * Notes on memory objects [i.e: ph7_value].
  18. * Internally, the PH7 virtual machine manipulates nearly all PHP values
  19. * [i.e: string,int,float,resource,object,bool,null..] as ph7_values structures.
  20. * Each ph7_values struct may cache multiple representations (string,
  21. * integer etc.) of the same value.
  22. */
  23. /*
  24. * Convert a 64-bit IEEE double into a 64-bit signed integer.
  25. * If the double is too large, return 0x8000000000000000.
  26. *
  27. * Most systems appear to do this simply by assigning ariables and without
  28. * the extra range tests.
  29. * But there are reports that windows throws an expection if the floating
  30. * point value is out of range.
  31. */
  32. static sxi64 MemObjRealToInt(ph7_value *pObj) {
  33. #ifdef PH7_OMIT_FLOATING_POINT
  34. /* Real and 64bit integer are the same when floating point arithmetic
  35. * is omitted from the build.
  36. */
  37. return pObj->rVal;
  38. #else
  39. /*
  40. ** Many compilers we encounter do not define constants for the
  41. ** minimum and maximum 64-bit integers, or they define them
  42. ** inconsistently. And many do not understand the "LL" notation.
  43. ** So we define our own static constants here using nothing
  44. ** larger than a 32-bit integer constant.
  45. */
  46. static const sxi64 maxInt = LARGEST_INT64;
  47. static const sxi64 minInt = SMALLEST_INT64;
  48. ph7_real r = pObj->rVal;
  49. if(r < (ph7_real)minInt) {
  50. return minInt;
  51. } else if(r > (ph7_real)maxInt) {
  52. /* minInt is correct here - not maxInt. It turns out that assigning
  53. ** a very large positive number to an integer results in a very large
  54. ** negative integer. This makes no sense, but it is what x86 hardware
  55. ** does so for compatibility we will do the same in software. */
  56. return minInt;
  57. } else {
  58. return (sxi64)r;
  59. }
  60. #endif
  61. }
  62. /*
  63. * Convert a raw token value typically a stream of digit [i.e: hex,octal,binary or decimal]
  64. * to a 64-bit integer.
  65. */
  66. PH7_PRIVATE sxi64 PH7_TokenValueToInt64(SyString *pVal) {
  67. sxi64 iVal = 0;
  68. if(pVal->nByte <= 0) {
  69. return 0;
  70. }
  71. if(pVal->zString[0] == '0') {
  72. sxi32 c;
  73. if(pVal->nByte == sizeof(char)) {
  74. return 0;
  75. }
  76. c = pVal->zString[1];
  77. if(c == 'x' || c == 'X') {
  78. /* Hex digit stream */
  79. SyHexStrToInt64(pVal->zString, pVal->nByte, (void *)&iVal, 0);
  80. } else if(c == 'b' || c == 'B') {
  81. /* Binary digit stream */
  82. SyBinaryStrToInt64(pVal->zString, pVal->nByte, (void *)&iVal, 0);
  83. } else {
  84. /* Octal digit stream */
  85. SyOctalStrToInt64(pVal->zString, pVal->nByte, (void *)&iVal, 0);
  86. }
  87. } else {
  88. /* Decimal digit stream */
  89. SyStrToInt64(pVal->zString, pVal->nByte, (void *)&iVal, 0);
  90. }
  91. return iVal;
  92. }
  93. /*
  94. * Return some kind of 64-bit integer value which is the best we can
  95. * do at representing the value that pObj describes as a string
  96. * representation.
  97. */
  98. static sxi64 MemObjStringToInt(ph7_value *pObj) {
  99. SyString sVal;
  100. SyStringInitFromBuf(&sVal, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
  101. return PH7_TokenValueToInt64(&sVal);
  102. }
  103. /*
  104. * Call a magic class method [i.e: __toString(),__toInt(),...]
  105. * Return SXRET_OK if the magic method is available and have been
  106. * successfully called. Any other return value indicates failure.
  107. */
  108. static sxi32 MemObjCallClassCastMethod(
  109. ph7_vm *pVm, /* VM that trigger the invocation */
  110. ph7_class_instance *pThis, /* Target class instance [i.e: Object] */
  111. const char *zMethod, /* Magic method name [i.e: __toString] */
  112. sxu32 nLen, /* Method name length */
  113. ph7_value *pResult /* OUT: Store the return value of the magic method here */
  114. ) {
  115. ph7_class_method *pMethod;
  116. /* Check if the method is available */
  117. pMethod = PH7_ClassExtractMethod(pThis->pClass, zMethod, nLen);
  118. if(pMethod == 0) {
  119. /* No such method */
  120. return SXERR_NOTFOUND;
  121. }
  122. /* Invoke the desired method */
  123. PH7_VmCallClassMethod(&(*pVm), &(*pThis), pMethod, &(*pResult), 0, 0);
  124. /* Method successfully called,pResult should hold the return value */
  125. return SXRET_OK;
  126. }
  127. /*
  128. * Return some kind of integer value which is the best we can
  129. * do at representing the value that pObj describes as an integer.
  130. * If pObj is an integer, then the value is exact. If pObj is
  131. * a floating-point then the value returned is the integer part.
  132. * If pObj is a string, then we make an attempt to convert it into
  133. * a integer and return that.
  134. * If pObj represents a NULL value, return 0.
  135. */
  136. static sxi64 MemObjIntValue(ph7_value *pObj) {
  137. sxi32 iFlags;
  138. iFlags = pObj->iFlags;
  139. if(iFlags & MEMOBJ_REAL) {
  140. return MemObjRealToInt(&(*pObj));
  141. } else if(iFlags & (MEMOBJ_INT | MEMOBJ_BOOL)) {
  142. return pObj->x.iVal;
  143. } else if(iFlags & MEMOBJ_STRING) {
  144. return MemObjStringToInt(&(*pObj));
  145. } else if(iFlags & MEMOBJ_NULL) {
  146. return 0;
  147. } else if(iFlags & MEMOBJ_HASHMAP) {
  148. ph7_hashmap *pMap = (ph7_hashmap *)pObj->x.pOther;
  149. sxu32 n = pMap->nEntry;
  150. PH7_HashmapUnref(pMap);
  151. /* Return total number of entries in the hashmap */
  152. return n;
  153. } else if(iFlags & MEMOBJ_OBJ) {
  154. ph7_value sResult;
  155. sxi64 iVal = 1;
  156. sxi32 rc;
  157. /* Invoke the [__toInt()] magic method if available [note that this is a symisc extension] */
  158. PH7_MemObjInit(pObj->pVm, &sResult);
  159. rc = MemObjCallClassCastMethod(pObj->pVm, (ph7_class_instance *)pObj->x.pOther,
  160. "__toInt", sizeof("__toInt") - 1, &sResult);
  161. if(rc == SXRET_OK && (sResult.iFlags & MEMOBJ_INT)) {
  162. /* Extract method return value */
  163. iVal = sResult.x.iVal;
  164. }
  165. PH7_ClassInstanceUnref((ph7_class_instance *)pObj->x.pOther);
  166. PH7_MemObjRelease(&sResult);
  167. return iVal;
  168. } else if(iFlags & MEMOBJ_RES) {
  169. return pObj->x.pOther != 0;
  170. }
  171. /* CANT HAPPEN */
  172. return 0;
  173. }
  174. /*
  175. * Return some kind of real value which is the best we can
  176. * do at representing the value that pObj describes as a real.
  177. * If pObj is a real, then the value is exact.If pObj is an
  178. * integer then the integer is promoted to real and that value
  179. * is returned.
  180. * If pObj is a string, then we make an attempt to convert it
  181. * into a real and return that.
  182. * If pObj represents a NULL value, return 0.0
  183. */
  184. static ph7_real MemObjRealValue(ph7_value *pObj) {
  185. sxi32 iFlags;
  186. iFlags = pObj->iFlags;
  187. if(iFlags & MEMOBJ_REAL) {
  188. return pObj->rVal;
  189. } else if(iFlags & (MEMOBJ_INT | MEMOBJ_BOOL)) {
  190. return (ph7_real)pObj->x.iVal;
  191. } else if(iFlags & MEMOBJ_STRING) {
  192. SyString sString;
  193. #ifdef PH7_OMIT_FLOATING_POINT
  194. ph7_real rVal = 0;
  195. #else
  196. ph7_real rVal = 0.0;
  197. #endif
  198. SyStringInitFromBuf(&sString, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
  199. if(SyBlobLength(&pObj->sBlob) > 0) {
  200. /* Convert as much as we can */
  201. #ifdef PH7_OMIT_FLOATING_POINT
  202. rVal = MemObjStringToInt(&(*pObj));
  203. #else
  204. SyStrToReal(sString.zString, sString.nByte, (void *)&rVal, 0);
  205. #endif
  206. }
  207. return rVal;
  208. } else if(iFlags & MEMOBJ_NULL) {
  209. #ifdef PH7_OMIT_FLOATING_POINT
  210. return 0;
  211. #else
  212. return 0.0;
  213. #endif
  214. } else if(iFlags & MEMOBJ_HASHMAP) {
  215. /* Return the total number of entries in the hashmap */
  216. ph7_hashmap *pMap = (ph7_hashmap *)pObj->x.pOther;
  217. ph7_real n = (ph7_real)pMap->nEntry;
  218. PH7_HashmapUnref(pMap);
  219. return n;
  220. } else if(iFlags & MEMOBJ_OBJ) {
  221. ph7_value sResult;
  222. ph7_real rVal = 1;
  223. sxi32 rc;
  224. /* Invoke the [__toFloat()] magic method if available [note that this is a symisc extension] */
  225. PH7_MemObjInit(pObj->pVm, &sResult);
  226. rc = MemObjCallClassCastMethod(pObj->pVm, (ph7_class_instance *)pObj->x.pOther,
  227. "__toFloat", sizeof("__toFloat") - 1, &sResult);
  228. if(rc == SXRET_OK && (sResult.iFlags & MEMOBJ_REAL)) {
  229. /* Extract method return value */
  230. rVal = sResult.rVal;
  231. }
  232. PH7_ClassInstanceUnref((ph7_class_instance *)pObj->x.pOther);
  233. PH7_MemObjRelease(&sResult);
  234. return rVal;
  235. } else if(iFlags & MEMOBJ_RES) {
  236. return (ph7_real)(pObj->x.pOther != 0);
  237. }
  238. /* NOT REACHED */
  239. return 0;
  240. }
  241. /*
  242. * Return the string representation of a given ph7_value.
  243. * This function never fail and always return SXRET_OK.
  244. */
  245. static sxi32 MemObjStringValue(SyBlob *pOut, ph7_value *pObj, sxu8 bStrictBool) {
  246. if(pObj->iFlags & MEMOBJ_REAL) {
  247. SyBlobFormat(&(*pOut), "%.15g", pObj->rVal);
  248. } else if(pObj->iFlags & MEMOBJ_INT) {
  249. SyBlobFormat(&(*pOut), "%qd", pObj->x.iVal);
  250. /* %qd (BSD quad) is equivalent to %lld in the libc printf */
  251. } else if(pObj->iFlags & MEMOBJ_BOOL) {
  252. if(pObj->x.iVal) {
  253. SyBlobAppend(&(*pOut), "TRUE", sizeof("TRUE") - 1);
  254. } else {
  255. if(!bStrictBool) {
  256. SyBlobAppend(&(*pOut), "FALSE", sizeof("FALSE") - 1);
  257. }
  258. }
  259. } else if(pObj->iFlags & MEMOBJ_HASHMAP) {
  260. SyBlobAppend(&(*pOut), "Array", sizeof("Array") - 1);
  261. PH7_HashmapUnref((ph7_hashmap *)pObj->x.pOther);
  262. } else if(pObj->iFlags & MEMOBJ_OBJ) {
  263. ph7_value sResult;
  264. sxi32 rc;
  265. /* Invoke the __toString() method if available */
  266. PH7_MemObjInit(pObj->pVm, &sResult);
  267. rc = MemObjCallClassCastMethod(pObj->pVm, (ph7_class_instance *)pObj->x.pOther,
  268. "__toString", sizeof("__toString") - 1, &sResult);
  269. if(rc == SXRET_OK && (sResult.iFlags & MEMOBJ_STRING) && SyBlobLength(&sResult.sBlob) > 0) {
  270. /* Expand method return value */
  271. SyBlobDup(&sResult.sBlob, pOut);
  272. } else {
  273. /* Expand "Object" as requested by the PHP language reference manual */
  274. SyBlobAppend(&(*pOut), "Object", sizeof("Object") - 1);
  275. }
  276. PH7_ClassInstanceUnref((ph7_class_instance *)pObj->x.pOther);
  277. PH7_MemObjRelease(&sResult);
  278. } else if(pObj->iFlags & MEMOBJ_RES) {
  279. SyBlobFormat(&(*pOut), "ResourceID_%#x", pObj->x.pOther);
  280. }
  281. return SXRET_OK;
  282. }
  283. /*
  284. * Return some kind of boolean value which is the best we can do
  285. * at representing the value that pObj describes as a boolean.
  286. * When converting to boolean, the following values are considered FALSE:
  287. * NULL
  288. * the boolean FALSE itself.
  289. * the integer 0 (zero).
  290. * the real 0.0 (zero).
  291. * the empty string,a stream of zero [i.e: "0","00","000",...] and the string
  292. * "false".
  293. * an array with zero elements.
  294. */
  295. static sxi32 MemObjBooleanValue(ph7_value *pObj) {
  296. sxi32 iFlags;
  297. iFlags = pObj->iFlags;
  298. if(iFlags & MEMOBJ_REAL) {
  299. #ifdef PH7_OMIT_FLOATING_POINT
  300. return pObj->rVal ? 1 : 0;
  301. #else
  302. return pObj->rVal != 0.0 ? 1 : 0;
  303. #endif
  304. } else if(iFlags & MEMOBJ_INT) {
  305. return pObj->x.iVal ? 1 : 0;
  306. } else if(iFlags & MEMOBJ_STRING) {
  307. SyString sString;
  308. SyStringInitFromBuf(&sString, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
  309. if(sString.nByte == 0) {
  310. /* Empty string */
  311. return 0;
  312. } else if((sString.nByte == sizeof("true") - 1 && SyStrnicmp(sString.zString, "true", sizeof("true") - 1) == 0) ||
  313. (sString.nByte == sizeof("on") - 1 && SyStrnicmp(sString.zString, "on", sizeof("on") - 1) == 0) ||
  314. (sString.nByte == sizeof("yes") - 1 && SyStrnicmp(sString.zString, "yes", sizeof("yes") - 1) == 0)) {
  315. return 1;
  316. } else if(sString.nByte == sizeof("false") - 1 && SyStrnicmp(sString.zString, "false", sizeof("false") - 1) == 0) {
  317. return 0;
  318. } else {
  319. const char *zIn, *zEnd;
  320. zIn = sString.zString;
  321. zEnd = &zIn[sString.nByte];
  322. while(zIn < zEnd && zIn[0] == '0') {
  323. zIn++;
  324. }
  325. return zIn >= zEnd ? 0 : 1;
  326. }
  327. } else if(iFlags & MEMOBJ_NULL) {
  328. return 0;
  329. } else if(iFlags & MEMOBJ_HASHMAP) {
  330. ph7_hashmap *pMap = (ph7_hashmap *)pObj->x.pOther;
  331. sxu32 n = pMap->nEntry;
  332. PH7_HashmapUnref(pMap);
  333. return n > 0 ? TRUE : FALSE;
  334. } else if(iFlags & MEMOBJ_OBJ) {
  335. ph7_value sResult;
  336. sxi32 iVal = 1;
  337. sxi32 rc;
  338. /* Invoke the __toBool() method if available [note that this is a symisc extension] */
  339. PH7_MemObjInit(pObj->pVm, &sResult);
  340. rc = MemObjCallClassCastMethod(pObj->pVm, (ph7_class_instance *)pObj->x.pOther,
  341. "__toBool", sizeof("__toBool") - 1, &sResult);
  342. if(rc == SXRET_OK && (sResult.iFlags & (MEMOBJ_INT | MEMOBJ_BOOL))) {
  343. /* Extract method return value */
  344. iVal = (sxi32)(sResult.x.iVal != 0); /* Stupid cc warning -W -Wall -O6 */
  345. }
  346. PH7_ClassInstanceUnref((ph7_class_instance *)pObj->x.pOther);
  347. PH7_MemObjRelease(&sResult);
  348. return iVal;
  349. } else if(iFlags & MEMOBJ_RES) {
  350. return pObj->x.pOther != 0;
  351. }
  352. /* NOT REACHED */
  353. return 0;
  354. }
  355. /*
  356. * If the ph7_value is of type real,try to make it an integer also.
  357. */
  358. static sxi32 MemObjTryIntger(ph7_value *pObj) {
  359. pObj->x.iVal = MemObjRealToInt(&(*pObj));
  360. /* Only mark the value as an integer if
  361. **
  362. ** (1) the round-trip conversion real->int->real is a no-op, and
  363. ** (2) The integer is neither the largest nor the smallest
  364. ** possible integer
  365. **
  366. ** The second and third terms in the following conditional enforces
  367. ** the second condition under the assumption that addition overflow causes
  368. ** values to wrap around. On x86 hardware, the third term is always
  369. ** true and could be omitted. But we leave it in because other
  370. ** architectures might behave differently.
  371. */
  372. if(pObj->rVal == (ph7_real)pObj->x.iVal && pObj->x.iVal > SMALLEST_INT64
  373. && pObj->x.iVal < LARGEST_INT64) {
  374. pObj->iFlags |= MEMOBJ_INT;
  375. }
  376. return SXRET_OK;
  377. }
  378. /*
  379. * Convert a ph7_value to type integer.Invalidate any prior representations.
  380. */
  381. PH7_PRIVATE sxi32 PH7_MemObjToInteger(ph7_value *pObj) {
  382. if((pObj->iFlags & MEMOBJ_INT) == 0) {
  383. /* Preform the conversion */
  384. pObj->x.iVal = MemObjIntValue(&(*pObj));
  385. /* Invalidate any prior representations */
  386. SyBlobRelease(&pObj->sBlob);
  387. MemObjSetType(pObj, MEMOBJ_INT);
  388. }
  389. return SXRET_OK;
  390. }
  391. /*
  392. * Convert a ph7_value to type real (Try to get an integer representation also).
  393. * Invalidate any prior representations
  394. */
  395. PH7_PRIVATE sxi32 PH7_MemObjToReal(ph7_value *pObj) {
  396. if((pObj->iFlags & MEMOBJ_REAL) == 0) {
  397. /* Preform the conversion */
  398. pObj->rVal = MemObjRealValue(&(*pObj));
  399. /* Invalidate any prior representations */
  400. SyBlobRelease(&pObj->sBlob);
  401. MemObjSetType(pObj, MEMOBJ_REAL);
  402. /* Try to get an integer representation */
  403. MemObjTryIntger(&(*pObj));
  404. }
  405. return SXRET_OK;
  406. }
  407. /*
  408. * Convert a ph7_value to type boolean.Invalidate any prior representations.
  409. */
  410. PH7_PRIVATE sxi32 PH7_MemObjToBool(ph7_value *pObj) {
  411. if((pObj->iFlags & MEMOBJ_BOOL) == 0) {
  412. /* Preform the conversion */
  413. pObj->x.iVal = MemObjBooleanValue(&(*pObj));
  414. /* Invalidate any prior representations */
  415. SyBlobRelease(&pObj->sBlob);
  416. MemObjSetType(pObj, MEMOBJ_BOOL);
  417. }
  418. return SXRET_OK;
  419. }
  420. /*
  421. * Convert a ph7_value to type string.Prior representations are NOT invalidated.
  422. */
  423. PH7_PRIVATE sxi32 PH7_MemObjToString(ph7_value *pObj) {
  424. sxi32 rc = SXRET_OK;
  425. if((pObj->iFlags & MEMOBJ_STRING) == 0) {
  426. /* Perform the conversion */
  427. SyBlobReset(&pObj->sBlob); /* Reset the internal buffer */
  428. rc = MemObjStringValue(&pObj->sBlob, &(*pObj), TRUE);
  429. MemObjSetType(pObj, MEMOBJ_STRING);
  430. }
  431. return rc;
  432. }
  433. /*
  434. * Nullify a ph7_value.In other words invalidate any prior
  435. * representation.
  436. */
  437. PH7_PRIVATE sxi32 PH7_MemObjToNull(ph7_value *pObj) {
  438. return PH7_MemObjRelease(pObj);
  439. }
  440. /*
  441. * Convert a ph7_value to type array.Invalidate any prior representations.
  442. * According to the PHP language reference manual.
  443. * For any of the types: integer, float, string, boolean converting a value
  444. * to an array results in an array with a single element with index zero
  445. * and the value of the scalar which was converted.
  446. */
  447. PH7_PRIVATE sxi32 PH7_MemObjToHashmap(ph7_value *pObj) {
  448. if((pObj->iFlags & MEMOBJ_HASHMAP) == 0) {
  449. ph7_hashmap *pMap;
  450. /* Allocate a new hashmap instance */
  451. pMap = PH7_NewHashmap(pObj->pVm, 0, 0);
  452. if(pMap == 0) {
  453. return SXERR_MEM;
  454. }
  455. if((pObj->iFlags & (MEMOBJ_NULL | MEMOBJ_RES)) == 0) {
  456. /*
  457. * According to the PHP language reference manual.
  458. * For any of the types: integer, float, string, boolean converting a value
  459. * to an array results in an array with a single element with index zero
  460. * and the value of the scalar which was converted.
  461. */
  462. if(pObj->iFlags & MEMOBJ_OBJ) {
  463. /* Object cast */
  464. PH7_ClassInstanceToHashmap((ph7_class_instance *)pObj->x.pOther, pMap);
  465. } else {
  466. /* Insert a single element */
  467. PH7_HashmapInsert(pMap, 0/* Automatic index assign */, &(*pObj));
  468. }
  469. SyBlobRelease(&pObj->sBlob);
  470. }
  471. /* Invalidate any prior representation */
  472. MemObjSetType(pObj, MEMOBJ_HASHMAP);
  473. pObj->x.pOther = pMap;
  474. }
  475. return SXRET_OK;
  476. }
  477. /*
  478. * Convert a ph7_value to type object.Invalidate any prior representations.
  479. * The new object is instantiated from the builtin stdClass().
  480. * The stdClass() class have a single attribute which is '$value'. This attribute
  481. * hold a copy of the converted ph7_value.
  482. * The internal of the stdClass is as follows:
  483. * class stdClass{
  484. * public $value;
  485. * public function __toInt(){ return (int)$this->value; }
  486. * public function __toBool(){ return (bool)$this->value; }
  487. * public function __toFloat(){ return (float)$this->value; }
  488. * public function __toString(){ return (string)$this->value; }
  489. * function __construct($v){ $this->value = $v; }"
  490. * }
  491. * Refer to the official documentation for more information.
  492. */
  493. PH7_PRIVATE sxi32 PH7_MemObjToObject(ph7_value *pObj) {
  494. if((pObj->iFlags & MEMOBJ_OBJ) == 0) {
  495. ph7_class_instance *pStd;
  496. ph7_class_method *pCons;
  497. ph7_class *pClass;
  498. ph7_vm *pVm;
  499. /* Point to the underlying VM */
  500. pVm = pObj->pVm;
  501. /* Point to the stdClass() */
  502. pClass = PH7_VmExtractClass(pVm, "stdClass", sizeof("stdClass") - 1, 0, 0);
  503. if(pClass == 0) {
  504. /* Can't happen,load null instead */
  505. PH7_MemObjRelease(pObj);
  506. return SXRET_OK;
  507. }
  508. /* Instanciate a new stdClass() object */
  509. pStd = PH7_NewClassInstance(pVm, pClass);
  510. if(pStd == 0) {
  511. /* Out of memory */
  512. PH7_MemObjRelease(pObj);
  513. return SXRET_OK;
  514. }
  515. /* Check if a constructor is available */
  516. pCons = PH7_ClassExtractMethod(pClass, "__construct", sizeof("__construct") - 1);
  517. if(pCons) {
  518. ph7_value *apArg[2];
  519. /* Invoke the constructor with one argument */
  520. apArg[0] = pObj;
  521. PH7_VmCallClassMethod(pVm, pStd, pCons, 0, 1, apArg);
  522. if(pStd->iRef < 1) {
  523. pStd->iRef = 1;
  524. }
  525. }
  526. /* Invalidate any prior representation */
  527. PH7_MemObjRelease(pObj);
  528. /* Save the new instance */
  529. pObj->x.pOther = pStd;
  530. MemObjSetType(pObj, MEMOBJ_OBJ);
  531. }
  532. return SXRET_OK;
  533. }
  534. /*
  535. * Return a pointer to the appropriate convertion method associated
  536. * with the given type.
  537. * Note on type juggling.
  538. * Accoding to the PHP language reference manual
  539. * PHP does not require (or support) explicit type definition in variable
  540. * declaration; a variable's type is determined by the context in which
  541. * the variable is used. That is to say, if a string value is assigned
  542. * to variable $var, $var becomes a string. If an integer value is then
  543. * assigned to $var, it becomes an integer.
  544. */
  545. PH7_PRIVATE ProcMemObjCast PH7_MemObjCastMethod(sxi32 iFlags) {
  546. if(iFlags & MEMOBJ_STRING) {
  547. return PH7_MemObjToString;
  548. } else if(iFlags & MEMOBJ_INT) {
  549. return PH7_MemObjToInteger;
  550. } else if(iFlags & MEMOBJ_REAL) {
  551. return PH7_MemObjToReal;
  552. } else if(iFlags & MEMOBJ_BOOL) {
  553. return PH7_MemObjToBool;
  554. } else if(iFlags & MEMOBJ_HASHMAP) {
  555. return PH7_MemObjToHashmap;
  556. } else if(iFlags & MEMOBJ_OBJ) {
  557. return PH7_MemObjToObject;
  558. }
  559. /* NULL cast */
  560. return PH7_MemObjToNull;
  561. }
  562. /*
  563. * Check whether the ph7_value is numeric [i.e: int/float/bool] or looks
  564. * like a numeric number [i.e: if the ph7_value is of type string.].
  565. * Return TRUE if numeric.FALSE otherwise.
  566. */
  567. PH7_PRIVATE sxi32 PH7_MemObjIsNumeric(ph7_value *pObj) {
  568. if(pObj->iFlags & (MEMOBJ_BOOL | MEMOBJ_INT | MEMOBJ_REAL)) {
  569. return TRUE;
  570. } else if(pObj->iFlags & (MEMOBJ_NULL | MEMOBJ_HASHMAP | MEMOBJ_OBJ | MEMOBJ_RES)) {
  571. return FALSE;
  572. } else if(pObj->iFlags & MEMOBJ_STRING) {
  573. SyString sStr;
  574. sxi32 rc;
  575. SyStringInitFromBuf(&sStr, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
  576. if(sStr.nByte <= 0) {
  577. /* Empty string */
  578. return FALSE;
  579. }
  580. /* Check if the string representation looks like a numeric number */
  581. rc = SyStrIsNumeric(sStr.zString, sStr.nByte, 0, 0);
  582. return rc == SXRET_OK ? TRUE : FALSE;
  583. }
  584. /* NOT REACHED */
  585. return FALSE;
  586. }
  587. /*
  588. * Check whether the ph7_value is empty.Return TRUE if empty.
  589. * FALSE otherwise.
  590. * An ph7_value is considered empty if the following are true:
  591. * NULL value.
  592. * Boolean FALSE.
  593. * Integer/Float with a 0 (zero) value.
  594. * An empty string or a stream of 0 (zero) [i.e: "0","00","000",...].
  595. * An empty array.
  596. * NOTE
  597. * OBJECT VALUE MUST NOT BE MODIFIED.
  598. */
  599. PH7_PRIVATE sxi32 PH7_MemObjIsEmpty(ph7_value *pObj) {
  600. if(pObj->iFlags & MEMOBJ_NULL) {
  601. return TRUE;
  602. } else if(pObj->iFlags & MEMOBJ_INT) {
  603. return pObj->x.iVal == 0 ? TRUE : FALSE;
  604. } else if(pObj->iFlags & MEMOBJ_REAL) {
  605. return pObj->rVal == (ph7_real)0 ? TRUE : FALSE;
  606. } else if(pObj->iFlags & MEMOBJ_BOOL) {
  607. return !pObj->x.iVal;
  608. } else if(pObj->iFlags & MEMOBJ_STRING) {
  609. if(SyBlobLength(&pObj->sBlob) <= 0) {
  610. return TRUE;
  611. } else {
  612. const char *zIn, *zEnd;
  613. zIn = (const char *)SyBlobData(&pObj->sBlob);
  614. zEnd = &zIn[SyBlobLength(&pObj->sBlob)];
  615. while(zIn < zEnd) {
  616. if(zIn[0] != '0') {
  617. break;
  618. }
  619. zIn++;
  620. }
  621. return zIn >= zEnd ? TRUE : FALSE;
  622. }
  623. } else if(pObj->iFlags & MEMOBJ_HASHMAP) {
  624. ph7_hashmap *pMap = (ph7_hashmap *)pObj->x.pOther;
  625. return pMap->nEntry == 0 ? TRUE : FALSE;
  626. } else if(pObj->iFlags & (MEMOBJ_OBJ | MEMOBJ_RES)) {
  627. return FALSE;
  628. }
  629. /* Assume empty by default */
  630. return TRUE;
  631. }
  632. /*
  633. * Convert a ph7_value so that it has types MEMOBJ_REAL or MEMOBJ_INT
  634. * or both.
  635. * Invalidate any prior representations. Every effort is made to force
  636. * the conversion, even if the input is a string that does not look
  637. * completely like a number.Convert as much of the string as we can
  638. * and ignore the rest.
  639. */
  640. PH7_PRIVATE sxi32 PH7_MemObjToNumeric(ph7_value *pObj) {
  641. if(pObj->iFlags & (MEMOBJ_INT | MEMOBJ_REAL | MEMOBJ_BOOL | MEMOBJ_NULL)) {
  642. if(pObj->iFlags & (MEMOBJ_BOOL | MEMOBJ_NULL)) {
  643. if(pObj->iFlags & MEMOBJ_NULL) {
  644. pObj->x.iVal = 0;
  645. }
  646. MemObjSetType(pObj, MEMOBJ_INT);
  647. }
  648. /* Already numeric */
  649. return SXRET_OK;
  650. }
  651. if(pObj->iFlags & MEMOBJ_STRING) {
  652. sxi32 rc = SXERR_INVALID;
  653. sxu8 bReal = FALSE;
  654. SyString sString;
  655. SyStringInitFromBuf(&sString, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
  656. /* Check if the given string looks like a numeric number */
  657. if(sString.nByte > 0) {
  658. rc = SyStrIsNumeric(sString.zString, sString.nByte, &bReal, 0);
  659. }
  660. if(bReal) {
  661. PH7_MemObjToReal(&(*pObj));
  662. } else {
  663. if(rc != SXRET_OK) {
  664. /* The input does not look at all like a number,set the value to 0 */
  665. pObj->x.iVal = 0;
  666. } else {
  667. /* Convert as much as we can */
  668. pObj->x.iVal = MemObjStringToInt(&(*pObj));
  669. }
  670. MemObjSetType(pObj, MEMOBJ_INT);
  671. SyBlobRelease(&pObj->sBlob);
  672. }
  673. } else if(pObj->iFlags & (MEMOBJ_OBJ | MEMOBJ_HASHMAP | MEMOBJ_RES)) {
  674. PH7_MemObjToInteger(pObj);
  675. } else {
  676. /* Perform a blind cast */
  677. PH7_MemObjToReal(&(*pObj));
  678. }
  679. return SXRET_OK;
  680. }
  681. /*
  682. * Try a get an integer representation of the given ph7_value.
  683. * If the ph7_value is not of type real,this function is a no-op.
  684. */
  685. PH7_PRIVATE sxi32 PH7_MemObjTryInteger(ph7_value *pObj) {
  686. if(pObj->iFlags & MEMOBJ_REAL) {
  687. /* Work only with reals */
  688. MemObjTryIntger(&(*pObj));
  689. }
  690. return SXRET_OK;
  691. }
  692. /*
  693. * Initialize a ph7_value to the null type.
  694. */
  695. PH7_PRIVATE sxi32 PH7_MemObjInit(ph7_vm *pVm, ph7_value *pObj) {
  696. /* Zero the structure */
  697. SyZero(pObj, sizeof(ph7_value));
  698. /* Initialize fields */
  699. pObj->pVm = pVm;
  700. SyBlobInit(&pObj->sBlob, &pVm->sAllocator);
  701. /* Set the NULL type */
  702. pObj->iFlags = MEMOBJ_NULL;
  703. return SXRET_OK;
  704. }
  705. /*
  706. * Initialize a ph7_value to the integer type.
  707. */
  708. PH7_PRIVATE sxi32 PH7_MemObjInitFromInt(ph7_vm *pVm, ph7_value *pObj, sxi64 iVal) {
  709. /* Zero the structure */
  710. SyZero(pObj, sizeof(ph7_value));
  711. /* Initialize fields */
  712. pObj->pVm = pVm;
  713. SyBlobInit(&pObj->sBlob, &pVm->sAllocator);
  714. /* Set the desired type */
  715. pObj->x.iVal = iVal;
  716. pObj->iFlags = MEMOBJ_INT;
  717. return SXRET_OK;
  718. }
  719. /*
  720. * Initialize a ph7_value to the boolean type.
  721. */
  722. PH7_PRIVATE sxi32 PH7_MemObjInitFromBool(ph7_vm *pVm, ph7_value *pObj, sxi32 iVal) {
  723. /* Zero the structure */
  724. SyZero(pObj, sizeof(ph7_value));
  725. /* Initialize fields */
  726. pObj->pVm = pVm;
  727. SyBlobInit(&pObj->sBlob, &pVm->sAllocator);
  728. /* Set the desired type */
  729. pObj->x.iVal = iVal ? 1 : 0;
  730. pObj->iFlags = MEMOBJ_BOOL;
  731. return SXRET_OK;
  732. }
  733. #if 0
  734. /*
  735. * Initialize a ph7_value to the real type.
  736. */
  737. PH7_PRIVATE sxi32 PH7_MemObjInitFromReal(ph7_vm *pVm, ph7_value *pObj, ph7_real rVal) {
  738. /* Zero the structure */
  739. SyZero(pObj, sizeof(ph7_value));
  740. /* Initialize fields */
  741. pObj->pVm = pVm;
  742. SyBlobInit(&pObj->sBlob, &pVm->sAllocator);
  743. /* Set the desired type */
  744. pObj->rVal = rVal;
  745. pObj->iFlags = MEMOBJ_REAL;
  746. return SXRET_OK;
  747. }
  748. #endif
  749. /*
  750. * Initialize a ph7_value to the array type.
  751. */
  752. PH7_PRIVATE sxi32 PH7_MemObjInitFromArray(ph7_vm *pVm, ph7_value *pObj, ph7_hashmap *pArray) {
  753. /* Zero the structure */
  754. SyZero(pObj, sizeof(ph7_value));
  755. /* Initialize fields */
  756. pObj->pVm = pVm;
  757. SyBlobInit(&pObj->sBlob, &pVm->sAllocator);
  758. /* Set the desired type */
  759. pObj->iFlags = MEMOBJ_HASHMAP;
  760. pObj->x.pOther = pArray;
  761. return SXRET_OK;
  762. }
  763. /*
  764. * Initialize a ph7_value to the string type.
  765. */
  766. PH7_PRIVATE sxi32 PH7_MemObjInitFromString(ph7_vm *pVm, ph7_value *pObj, const SyString *pVal) {
  767. /* Zero the structure */
  768. SyZero(pObj, sizeof(ph7_value));
  769. /* Initialize fields */
  770. pObj->pVm = pVm;
  771. SyBlobInit(&pObj->sBlob, &pVm->sAllocator);
  772. if(pVal) {
  773. /* Append contents */
  774. SyBlobAppend(&pObj->sBlob, (const void *)pVal->zString, pVal->nByte);
  775. }
  776. /* Set the desired type */
  777. pObj->iFlags = MEMOBJ_STRING;
  778. return SXRET_OK;
  779. }
  780. /*
  781. * Append some contents to the internal buffer of a given ph7_value.
  782. * If the given ph7_value is not of type string,this function
  783. * invalidate any prior representation and set the string type.
  784. * Then a simple append operation is performed.
  785. */
  786. PH7_PRIVATE sxi32 PH7_MemObjStringAppend(ph7_value *pObj, const char *zData, sxu32 nLen) {
  787. sxi32 rc;
  788. if((pObj->iFlags & MEMOBJ_STRING) == 0) {
  789. /* Invalidate any prior representation */
  790. PH7_MemObjRelease(pObj);
  791. MemObjSetType(pObj, MEMOBJ_STRING);
  792. }
  793. /* Append contents */
  794. rc = SyBlobAppend(&pObj->sBlob, zData, nLen);
  795. return rc;
  796. }
  797. #if 0
  798. /*
  799. * Format and append some contents to the internal buffer of a given ph7_value.
  800. * If the given ph7_value is not of type string,this function invalidate
  801. * any prior representation and set the string type.
  802. * Then a simple format and append operation is performed.
  803. */
  804. PH7_PRIVATE sxi32 PH7_MemObjStringFormat(ph7_value *pObj, const char *zFormat, va_list ap) {
  805. sxi32 rc;
  806. if((pObj->iFlags & MEMOBJ_STRING) == 0) {
  807. /* Invalidate any prior representation */
  808. PH7_MemObjRelease(pObj);
  809. MemObjSetType(pObj, MEMOBJ_STRING);
  810. }
  811. /* Format and append contents */
  812. rc = SyBlobFormatAp(&pObj->sBlob, zFormat, ap);
  813. return rc;
  814. }
  815. #endif
  816. /*
  817. * Duplicate the contents of a ph7_value.
  818. */
  819. PH7_PRIVATE sxi32 PH7_MemObjStore(ph7_value *pSrc, ph7_value *pDest) {
  820. ph7_class_instance *pObj = 0;
  821. ph7_hashmap *pMap = 0;
  822. sxi32 rc;
  823. if(pSrc->iFlags & MEMOBJ_HASHMAP) {
  824. /* Increment reference count */
  825. ((ph7_hashmap *)pSrc->x.pOther)->iRef++;
  826. } else if(pSrc->iFlags & MEMOBJ_OBJ) {
  827. /* Increment reference count */
  828. ((ph7_class_instance *)pSrc->x.pOther)->iRef++;
  829. }
  830. if(pDest->iFlags & MEMOBJ_HASHMAP) {
  831. pMap = (ph7_hashmap *)pDest->x.pOther;
  832. } else if(pDest->iFlags & MEMOBJ_OBJ) {
  833. pObj = (ph7_class_instance *)pDest->x.pOther;
  834. }
  835. SyMemcpy((const void *) & (*pSrc), &(*pDest), sizeof(ph7_value) - (sizeof(ph7_vm *) + sizeof(SyBlob) + sizeof(sxu32)));
  836. pDest->iFlags &= ~MEMOBJ_AUX;
  837. rc = SXRET_OK;
  838. if(SyBlobLength(&pSrc->sBlob) > 0) {
  839. SyBlobReset(&pDest->sBlob);
  840. rc = SyBlobDup(&pSrc->sBlob, &pDest->sBlob);
  841. } else {
  842. if(SyBlobLength(&pDest->sBlob) > 0) {
  843. SyBlobRelease(&pDest->sBlob);
  844. }
  845. }
  846. if(pMap) {
  847. PH7_HashmapUnref(pMap);
  848. } else if(pObj) {
  849. PH7_ClassInstanceUnref(pObj);
  850. }
  851. return rc;
  852. }
  853. /*
  854. * Duplicate the contents of a ph7_value but do not copy internal
  855. * buffer contents,simply point to it.
  856. */
  857. PH7_PRIVATE sxi32 PH7_MemObjLoad(ph7_value *pSrc, ph7_value *pDest) {
  858. SyMemcpy((const void *) & (*pSrc), &(*pDest),
  859. sizeof(ph7_value) - (sizeof(ph7_vm *) + sizeof(SyBlob) + sizeof(sxu32)));
  860. if(pSrc->iFlags & MEMOBJ_HASHMAP) {
  861. /* Increment reference count */
  862. ((ph7_hashmap *)pSrc->x.pOther)->iRef++;
  863. } else if(pSrc->iFlags & MEMOBJ_OBJ) {
  864. /* Increment reference count */
  865. ((ph7_class_instance *)pSrc->x.pOther)->iRef++;
  866. }
  867. if(SyBlobLength(&pDest->sBlob) > 0) {
  868. SyBlobRelease(&pDest->sBlob);
  869. }
  870. if(SyBlobLength(&pSrc->sBlob) > 0) {
  871. SyBlobReadOnly(&pDest->sBlob, SyBlobData(&pSrc->sBlob), SyBlobLength(&pSrc->sBlob));
  872. }
  873. return SXRET_OK;
  874. }
  875. /*
  876. * Invalidate any prior representation of a given ph7_value.
  877. */
  878. PH7_PRIVATE sxi32 PH7_MemObjRelease(ph7_value *pObj) {
  879. if((pObj->iFlags & MEMOBJ_NULL) == 0) {
  880. if(pObj->iFlags & MEMOBJ_HASHMAP) {
  881. PH7_HashmapUnref((ph7_hashmap *)pObj->x.pOther);
  882. } else if(pObj->iFlags & MEMOBJ_OBJ) {
  883. PH7_ClassInstanceUnref((ph7_class_instance *)pObj->x.pOther);
  884. }
  885. /* Release the internal buffer */
  886. SyBlobRelease(&pObj->sBlob);
  887. /* Invalidate any prior representation */
  888. pObj->iFlags = MEMOBJ_NULL;
  889. }
  890. return SXRET_OK;
  891. }
  892. /*
  893. * Compare two ph7_values.
  894. * Return 0 if the values are equals, > 0 if pObj1 is greater than pObj2
  895. * or < 0 if pObj2 is greater than pObj1.
  896. * Type comparison table taken from the PHP language reference manual.
  897. * Comparisons of $x with PHP functions Expression
  898. * gettype() empty() is_null() isset() boolean : if($x)
  899. * $x = ""; string TRUE FALSE TRUE FALSE
  900. * $x = null NULL TRUE TRUE FALSE FALSE
  901. * var $x; NULL TRUE TRUE FALSE FALSE
  902. * $x is undefined NULL TRUE TRUE FALSE FALSE
  903. * $x = array(); array TRUE FALSE TRUE FALSE
  904. * $x = false; boolean TRUE FALSE TRUE FALSE
  905. * $x = true; boolean FALSE FALSE TRUE TRUE
  906. * $x = 1; integer FALSE FALSE TRUE TRUE
  907. * $x = 42; integer FALSE FALSE TRUE TRUE
  908. * $x = 0; integer TRUE FALSE TRUE FALSE
  909. * $x = -1; integer FALSE FALSE TRUE TRUE
  910. * $x = "1"; string FALSE FALSE TRUE TRUE
  911. * $x = "0"; string TRUE FALSE TRUE FALSE
  912. * $x = "-1"; string FALSE FALSE TRUE TRUE
  913. * $x = "php"; string FALSE FALSE TRUE TRUE
  914. * $x = "true"; string FALSE FALSE TRUE TRUE
  915. * $x = "false"; string FALSE FALSE TRUE TRUE
  916. * Loose comparisons with ==
  917. * TRUE FALSE 1 0 -1 "1" "0" "-1" NULL array() "php" ""
  918. * TRUE TRUE FALSE TRUE FALSE TRUE TRUE FALSE TRUE FALSE FALSE TRUE FALSE
  919. * FALSE FALSE TRUE FALSE TRUE FALSE FALSE TRUE FALSE TRUE TRUE FALSE TRUE
  920. * 1 TRUE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE
  921. * 0 FALSE TRUE FALSE TRUE FALSE FALSE TRUE FALSE TRUE FALSE TRUE TRUE
  922. * -1 TRUE FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
  923. * "1" TRUE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE
  924. * "0" FALSE TRUE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
  925. * "-1" TRUE FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
  926. * NULL FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE TRUE TRUE FALSE TRUE
  927. * array() FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE TRUE FALSE FALSE
  928. * "php" TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
  929. * "" FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE TRUE FALSE FALSE TRUE
  930. * Strict comparisons with ===
  931. * TRUE FALSE 1 0 -1 "1" "0" "-1" NULL array() "php" ""
  932. * TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
  933. * FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
  934. * 1 FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
  935. * 0 FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
  936. * -1 FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
  937. * "1" FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE
  938. * "0" FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
  939. * "-1" FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
  940. * NULL FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE
  941. * array() FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE
  942. * "php" FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
  943. * "" FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE
  944. */
  945. PH7_PRIVATE sxi32 PH7_MemObjCmp(ph7_value *pObj1, ph7_value *pObj2, int bStrict, int iNest) {
  946. sxi32 iComb;
  947. sxi32 rc;
  948. if(bStrict) {
  949. sxi32 iF1, iF2;
  950. /* Strict comparisons with === */
  951. iF1 = pObj1->iFlags & ~MEMOBJ_AUX;
  952. iF2 = pObj2->iFlags & ~MEMOBJ_AUX;
  953. if(iF1 != iF2) {
  954. /* Not of the same type */
  955. return 1;
  956. }
  957. }
  958. /* Combine flag together */
  959. iComb = pObj1->iFlags | pObj2->iFlags;
  960. if(iComb & (MEMOBJ_NULL | MEMOBJ_RES | MEMOBJ_BOOL)) {
  961. /* Convert to boolean: Keep in mind FALSE < TRUE */
  962. if((pObj1->iFlags & MEMOBJ_BOOL) == 0) {
  963. PH7_MemObjToBool(pObj1);
  964. }
  965. if((pObj2->iFlags & MEMOBJ_BOOL) == 0) {
  966. PH7_MemObjToBool(pObj2);
  967. }
  968. return (sxi32)((pObj1->x.iVal != 0) - (pObj2->x.iVal != 0));
  969. } else if(iComb & MEMOBJ_HASHMAP) {
  970. /* Hashmap aka 'array' comparison */
  971. if((pObj1->iFlags & MEMOBJ_HASHMAP) == 0) {
  972. /* Array is always greater */
  973. return -1;
  974. }
  975. if((pObj2->iFlags & MEMOBJ_HASHMAP) == 0) {
  976. /* Array is always greater */
  977. return 1;
  978. }
  979. /* Perform the comparison */
  980. rc = PH7_HashmapCmp((ph7_hashmap *)pObj1->x.pOther, (ph7_hashmap *)pObj2->x.pOther, bStrict);
  981. return rc;
  982. } else if(iComb & MEMOBJ_OBJ) {
  983. /* Object comparison */
  984. if((pObj1->iFlags & MEMOBJ_OBJ) == 0) {
  985. /* Object is always greater */
  986. return -1;
  987. }
  988. if((pObj2->iFlags & MEMOBJ_OBJ) == 0) {
  989. /* Object is always greater */
  990. return 1;
  991. }
  992. /* Perform the comparison */
  993. rc = PH7_ClassInstanceCmp((ph7_class_instance *)pObj1->x.pOther, (ph7_class_instance *)pObj2->x.pOther, bStrict, iNest);
  994. return rc;
  995. } else if(iComb & MEMOBJ_STRING) {
  996. SyString s1, s2;
  997. if(!bStrict) {
  998. /*
  999. * According to the PHP language reference manual:
  1000. *
  1001. * If you compare a number with a string or the comparison involves numerical
  1002. * strings, then each string is converted to a number and the comparison
  1003. * performed numerically.
  1004. */
  1005. if(PH7_MemObjIsNumeric(pObj1)) {
  1006. /* Perform a numeric comparison */
  1007. goto Numeric;
  1008. }
  1009. if(PH7_MemObjIsNumeric(pObj2)) {
  1010. /* Perform a numeric comparison */
  1011. goto Numeric;
  1012. }
  1013. }
  1014. /* Perform a strict string comparison.*/
  1015. if((pObj1->iFlags & MEMOBJ_STRING) == 0) {
  1016. PH7_MemObjToString(pObj1);
  1017. }
  1018. if((pObj2->iFlags & MEMOBJ_STRING) == 0) {
  1019. PH7_MemObjToString(pObj2);
  1020. }
  1021. SyStringInitFromBuf(&s1, SyBlobData(&pObj1->sBlob), SyBlobLength(&pObj1->sBlob));
  1022. SyStringInitFromBuf(&s2, SyBlobData(&pObj2->sBlob), SyBlobLength(&pObj2->sBlob));
  1023. /*
  1024. * Strings are compared using memcmp(). If one value is an exact prefix of the
  1025. * other, then the shorter value is less than the longer value.
  1026. */
  1027. rc = SyMemcmp((const void *)s1.zString, (const void *)s2.zString, SXMIN(s1.nByte, s2.nByte));
  1028. if(rc == 0) {
  1029. if(s1.nByte != s2.nByte) {
  1030. rc = s1.nByte < s2.nByte ? -1 : 1;
  1031. }
  1032. }
  1033. return rc;
  1034. } else if(iComb & (MEMOBJ_INT | MEMOBJ_REAL)) {
  1035. Numeric:
  1036. /* Perform a numeric comparison if one of the operand is numeric(integer or real) */
  1037. if((pObj1->iFlags & (MEMOBJ_INT | MEMOBJ_REAL)) == 0) {
  1038. PH7_MemObjToNumeric(pObj1);
  1039. }
  1040. if((pObj2->iFlags & (MEMOBJ_INT | MEMOBJ_REAL)) == 0) {
  1041. PH7_MemObjToNumeric(pObj2);
  1042. }
  1043. if((pObj1->iFlags & pObj2->iFlags & MEMOBJ_INT) == 0) {
  1044. /*
  1045. * Symisc eXtension to the PHP language:
  1046. * Floating point comparison is introduced and works as expected.
  1047. */
  1048. ph7_real r1, r2;
  1049. /* Compare as reals */
  1050. if((pObj1->iFlags & MEMOBJ_REAL) == 0) {
  1051. PH7_MemObjToReal(pObj1);
  1052. }
  1053. r1 = pObj1->rVal;
  1054. if((pObj2->iFlags & MEMOBJ_REAL) == 0) {
  1055. PH7_MemObjToReal(pObj2);
  1056. }
  1057. r2 = pObj2->rVal;
  1058. if(r1 > r2) {
  1059. return 1;
  1060. } else if(r1 < r2) {
  1061. return -1;
  1062. }
  1063. return 0;
  1064. } else {
  1065. /* Integer comparison */
  1066. if(pObj1->x.iVal > pObj2->x.iVal) {
  1067. return 1;
  1068. } else if(pObj1->x.iVal < pObj2->x.iVal) {
  1069. return -1;
  1070. }
  1071. return 0;
  1072. }
  1073. }
  1074. /* NOT REACHED */
  1075. return 0;
  1076. }
  1077. /*
  1078. * Perform an addition operation of two ph7_values.
  1079. * The reason this function is implemented here rather than 'vm.c'
  1080. * is that the '+' operator is overloaded.
  1081. * That is,the '+' operator is used for arithmetic operation and also
  1082. * used for operation on arrays [i.e: union]. When used with an array
  1083. * The + operator returns the right-hand array appended to the left-hand array.
  1084. * For keys that exist in both arrays, the elements from the left-hand array
  1085. * will be used, and the matching elements from the right-hand array will
  1086. * be ignored.
  1087. * This function take care of handling all the scenarios.
  1088. */
  1089. PH7_PRIVATE sxi32 PH7_MemObjAdd(ph7_value *pObj1, ph7_value *pObj2, int bAddStore) {
  1090. if(((pObj1->iFlags | pObj2->iFlags) & MEMOBJ_HASHMAP) == 0) {
  1091. /* Arithemtic operation */
  1092. PH7_MemObjToNumeric(pObj1);
  1093. PH7_MemObjToNumeric(pObj2);
  1094. if((pObj1->iFlags | pObj2->iFlags) & MEMOBJ_REAL) {
  1095. /* Floating point arithmetic */
  1096. ph7_real a, b;
  1097. if((pObj1->iFlags & MEMOBJ_REAL) == 0) {
  1098. PH7_MemObjToReal(pObj1);
  1099. }
  1100. if((pObj2->iFlags & MEMOBJ_REAL) == 0) {
  1101. PH7_MemObjToReal(pObj2);
  1102. }
  1103. a = pObj1->rVal;
  1104. b = pObj2->rVal;
  1105. pObj1->rVal = a + b;
  1106. MemObjSetType(pObj1, MEMOBJ_REAL);
  1107. /* Try to get an integer representation also */
  1108. MemObjTryIntger(&(*pObj1));
  1109. } else {
  1110. /* Integer arithmetic */
  1111. sxi64 a, b;
  1112. a = pObj1->x.iVal;
  1113. b = pObj2->x.iVal;
  1114. pObj1->x.iVal = a + b;
  1115. MemObjSetType(pObj1, MEMOBJ_INT);
  1116. }
  1117. } else {
  1118. if((pObj1->iFlags | pObj2->iFlags) & MEMOBJ_HASHMAP) {
  1119. ph7_hashmap *pMap;
  1120. sxi32 rc;
  1121. if(bAddStore) {
  1122. /* Do not duplicate the hashmap,use the left one since its an add&store operation.
  1123. */
  1124. if((pObj1->iFlags & MEMOBJ_HASHMAP) == 0) {
  1125. /* Force a hashmap cast */
  1126. rc = PH7_MemObjToHashmap(pObj1);
  1127. if(rc != SXRET_OK) {
  1128. PH7_VmThrowError(pObj1->pVm, 0, PH7_CTX_ERR, "PH7 is running out of memory while creating array");
  1129. return rc;
  1130. }
  1131. }
  1132. /* Point to the structure that describe the hashmap */
  1133. pMap = (ph7_hashmap *)pObj1->x.pOther;
  1134. } else {
  1135. /* Create a new hashmap */
  1136. pMap = PH7_NewHashmap(pObj1->pVm, 0, 0);
  1137. if(pMap == 0) {
  1138. PH7_VmThrowError(pObj1->pVm, 0, PH7_CTX_ERR, "PH7 is running out of memory while creating array");
  1139. return SXERR_MEM;
  1140. }
  1141. }
  1142. if(!bAddStore) {
  1143. if(pObj1->iFlags & MEMOBJ_HASHMAP) {
  1144. /* Perform a hashmap duplication */
  1145. PH7_HashmapDup((ph7_hashmap *)pObj1->x.pOther, pMap);
  1146. } else {
  1147. if((pObj1->iFlags & MEMOBJ_NULL) == 0) {
  1148. /* Simple insertion */
  1149. PH7_HashmapInsert(pMap, 0, pObj1);
  1150. }
  1151. }
  1152. }
  1153. /* Perform the union */
  1154. if(pObj2->iFlags & MEMOBJ_HASHMAP) {
  1155. PH7_HashmapUnion(pMap, (ph7_hashmap *)pObj2->x.pOther);
  1156. } else {
  1157. if((pObj2->iFlags & MEMOBJ_NULL) == 0) {
  1158. /* Simple insertion */
  1159. PH7_HashmapInsert(pMap, 0, pObj2);
  1160. }
  1161. }
  1162. /* Reflect the change */
  1163. if(pObj1->iFlags & MEMOBJ_STRING) {
  1164. SyBlobRelease(&pObj1->sBlob);
  1165. }
  1166. pObj1->x.pOther = pMap;
  1167. MemObjSetType(pObj1, MEMOBJ_HASHMAP);
  1168. }
  1169. }
  1170. return SXRET_OK;
  1171. }
  1172. /*
  1173. * Return a printable representation of the type of a given
  1174. * ph7_value.
  1175. */
  1176. PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) {
  1177. const char *zType = "";
  1178. if(pVal->iFlags & MEMOBJ_NULL) {
  1179. zType = "null";
  1180. } else if(pVal->iFlags & MEMOBJ_INT) {
  1181. zType = "int";
  1182. } else if(pVal->iFlags & MEMOBJ_REAL) {
  1183. zType = "float";
  1184. } else if(pVal->iFlags & MEMOBJ_STRING) {
  1185. zType = "string";
  1186. } else if(pVal->iFlags & MEMOBJ_BOOL) {
  1187. zType = "bool";
  1188. } else if(pVal->iFlags & MEMOBJ_HASHMAP) {
  1189. zType = "array";
  1190. } else if(pVal->iFlags & MEMOBJ_OBJ) {
  1191. zType = "object";
  1192. } else if(pVal->iFlags & MEMOBJ_RES) {
  1193. zType = "resource";
  1194. }
  1195. return zType;
  1196. }
  1197. /*
  1198. * Dump a ph7_value [i.e: get a printable representation of it's type and contents.].
  1199. * Store the dump in the given blob.
  1200. */
  1201. PH7_PRIVATE sxi32 PH7_MemObjDump(
  1202. SyBlob *pOut, /* Store the dump here */
  1203. ph7_value *pObj, /* Dump this */
  1204. int ShowType, /* TRUE to output value type */
  1205. int nTab, /* # of Whitespace to insert */
  1206. int nDepth, /* Nesting level */
  1207. int isRef /* TRUE if referenced object */
  1208. ) {
  1209. sxi32 rc = SXRET_OK;
  1210. const char *zType;
  1211. int i;
  1212. for(i = 0 ; i < nTab ; i++) {
  1213. SyBlobAppend(&(*pOut), " ", sizeof(char));
  1214. }
  1215. if(ShowType) {
  1216. if(isRef) {
  1217. SyBlobAppend(&(*pOut), "&", sizeof(char));
  1218. }
  1219. /* Get value type first */
  1220. zType = PH7_MemObjTypeDump(pObj);
  1221. SyBlobAppend(&(*pOut), zType, SyStrlen(zType));
  1222. }
  1223. if((pObj->iFlags & MEMOBJ_NULL) == 0) {
  1224. if(ShowType) {
  1225. SyBlobAppend(&(*pOut), "(", sizeof(char));
  1226. }
  1227. if(pObj->iFlags & MEMOBJ_HASHMAP) {
  1228. /* Dump hashmap entries */
  1229. rc = PH7_HashmapDump(&(*pOut), (ph7_hashmap *)pObj->x.pOther, ShowType, nTab + 1, nDepth + 1);
  1230. } else if(pObj->iFlags & MEMOBJ_OBJ) {
  1231. /* Dump class instance attributes */
  1232. rc = PH7_ClassInstanceDump(&(*pOut), (ph7_class_instance *)pObj->x.pOther, ShowType, nTab + 1, nDepth + 1);
  1233. } else {
  1234. SyBlob *pContents = &pObj->sBlob;
  1235. /* Get a printable representation of the contents */
  1236. if((pObj->iFlags & MEMOBJ_STRING) == 0) {
  1237. MemObjStringValue(&(*pOut), &(*pObj), FALSE);
  1238. } else {
  1239. /* Append length first */
  1240. if(ShowType) {
  1241. SyBlobFormat(&(*pOut), "%u '", SyBlobLength(&pObj->sBlob));
  1242. }
  1243. if(SyBlobLength(pContents) > 0) {
  1244. SyBlobAppend(&(*pOut), SyBlobData(pContents), SyBlobLength(pContents));
  1245. }
  1246. if(ShowType) {
  1247. SyBlobAppend(&(*pOut), "'", sizeof(char));
  1248. }
  1249. }
  1250. }
  1251. if(ShowType) {
  1252. if((pObj->iFlags & (MEMOBJ_HASHMAP | MEMOBJ_OBJ)) == 0) {
  1253. SyBlobAppend(&(*pOut), ")", sizeof(char));
  1254. }
  1255. }
  1256. }
  1257. #ifdef __WINNT__
  1258. SyBlobAppend(&(*pOut), "\r\n", sizeof("\r\n") - 1);
  1259. #else
  1260. SyBlobAppend(&(*pOut), "\n", sizeof(char));
  1261. #endif
  1262. return rc;
  1263. }