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.

1401 lines
46 KiB

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