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.

1346 lines
44 KiB

/**
* @PROJECT PH7 Engine for the AerScript Interpreter
* @COPYRIGHT See COPYING in the top level directory
* @FILE engine/memobj.c
* @DESCRIPTION Low-level indexed memory objects for the PH7 Engine
* @DEVELOPERS Symisc Systems <devel@symisc.net>
* Rafal Kupiec <belliash@codingworkshop.eu.org>
*/
#include "ph7int.h"
/* This file handle low-level stuff related to indexed memory objects [i.e: ph7_value] */
/*
* Notes on memory objects [i.e: ph7_value].
* Internally, the PH7 virtual machine manipulates nearly all PHP values
* [i.e: string,int,float,resource,object,bool,null..] as ph7_values structures.
* Each ph7_values struct may cache multiple representations (string,
* integer etc.) of the same value.
*/
/*
* Convert a 64-bit IEEE double into a 64-bit signed integer.
* If the double is too large, return 0x8000000000000000.
*
* Most systems appear to do this simply by assigning variables and without
* the extra range tests.
3 years ago
* But there are reports that windows throws an expection if the floating
* point value is out of range.
*/
3 years ago
static sxi64 MemObjRealToInt(ph7_value *pObj) {
/*
** Many compilers we encounter do not define constants for the
** minimum and maximum 64-bit integers, or they define them
** inconsistently. And many do not understand the "LL" notation.
** So we define our own static constants here using nothing
** larger than a 32-bit integer constant.
*/
static const sxi64 maxInt = LARGEST_INT64;
static const sxi64 minInt = SMALLEST_INT64;
ph7_real r = pObj->x.rVal;
3 years ago
if(r < (ph7_real)minInt) {
return minInt;
} else if(r > (ph7_real)maxInt) {
/* minInt is correct here - not maxInt. It turns out that assigning
** a very large positive number to an integer results in a very large
** negative integer. This makes no sense, but it is what x86 hardware
** does so for compatibility we will do the same in software. */
return minInt;
} else {
return (sxi64)r;
}
}
/*
3 years ago
* Convert a raw token value typically a stream of digit [i.e: hex,octal,binary or decimal]
* to a 64-bit integer.
*/
3 years ago
PH7_PRIVATE sxi64 PH7_TokenValueToInt64(SyString *pVal) {
sxi64 iVal = 0;
3 years ago
if(pVal->nByte <= 0) {
return 0;
}
3 years ago
if(pVal->zString[0] == '0') {
sxi32 c;
3 years ago
if(pVal->nByte == sizeof(char)) {
return 0;
}
c = pVal->zString[1];
3 years ago
if(c == 'x' || c == 'X') {
/* Hex digit stream */
3 years ago
SyHexStrToInt64(pVal->zString, pVal->nByte, (void *)&iVal, 0);
} else if(c == 'b' || c == 'B') {
/* Binary digit stream */
3 years ago
SyBinaryStrToInt64(pVal->zString, pVal->nByte, (void *)&iVal, 0);
} else {
/* Octal digit stream */
3 years ago
SyOctalStrToInt64(pVal->zString, pVal->nByte, (void *)&iVal, 0);
}
3 years ago
} else {
/* Decimal digit stream */
3 years ago
SyStrToInt64(pVal->zString, pVal->nByte, (void *)&iVal, 0);
}
return iVal;
}
/*
* Return some kind of 64-bit integer value which is the best we can
* do at representing the value that pObj describes as a string
* representation.
*/
3 years ago
static sxi64 MemObjStringToInt(ph7_value *pObj) {
SyString sVal;
3 years ago
SyStringInitFromBuf(&sVal, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
return PH7_TokenValueToInt64(&sVal);
}
/*
* Call a magic class method [i.e: __toString(),__toInt(),...]
* Return SXRET_OK if the magic method is available and have been
* successfully called. Any other return value indicates failure.
*/
static sxi32 MemObjCallClassCastMethod(
ph7_vm *pVm, /* VM that trigger the invocation */
ph7_class_instance *pThis, /* Target class instance [i.e: Object] */
const char *zMethod, /* Magic method name [i.e: __toString] */
sxu32 nLen, /* Method name length */
ph7_value *pResult /* OUT: Store the return value of the magic method here */
3 years ago
) {
ph7_class_method *pMethod = 0;
/* Check if the method is available */
if(pThis) {
pMethod = PH7_ClassExtractMethod(pThis->pClass, zMethod, nLen);
}
3 years ago
if(pMethod == 0) {
/* No such method */
return SXERR_NOTFOUND;
}
/* Invoke the desired method */
3 years ago
PH7_VmCallClassMethod(&(*pVm), &(*pThis), pMethod, &(*pResult), 0, 0);
/* Method successfully called,pResult should hold the return value */
return SXRET_OK;
}
/*
* Return some kind of integer value which is the best we can
* do at representing the value that pObj describes as an integer.
* If pObj is an integer, then the value is exact. If pObj is
* a floating-point then the value returned is the integer part.
* If pObj is a string, then we make an attempt to convert it into
3 years ago
* a integer and return that.
* If pObj represents a NULL value, return 0.
*/
3 years ago
static sxi64 MemObjIntValue(ph7_value *pObj) {
sxi32 nType;
nType = pObj->nType;
if(nType & MEMOBJ_REAL) {
return MemObjRealToInt(&(*pObj));
} else if(nType & (MEMOBJ_INT | MEMOBJ_BOOL | MEMOBJ_CHAR)) {
return pObj->x.iVal;
} else if(nType & MEMOBJ_STRING) {
return MemObjStringToInt(&(*pObj));
} else if(nType & (MEMOBJ_CALL | MEMOBJ_NULL | MEMOBJ_VOID)) {
return 0;
} else if(nType & MEMOBJ_HASHMAP) {
ph7_hashmap *pMap = (ph7_hashmap *)pObj->x.pOther;
sxu32 n = pMap->nEntry;
PH7_HashmapUnref(pMap);
/* Return total number of entries in the hashmap */
3 years ago
return n;
} else if(nType & MEMOBJ_OBJ) {
ph7_value sResult;
sxi64 iVal = 1;
sxi32 rc;
/* Invoke the [__toInt()] magic method if available [note that this is a symisc extension] */
3 years ago
PH7_MemObjInit(pObj->pVm, &sResult);
rc = MemObjCallClassCastMethod(pObj->pVm, (ph7_class_instance *)pObj->x.pOther,
"__toInt", sizeof("__toInt") - 1, &sResult);
if(rc == SXRET_OK && (sResult.nType & MEMOBJ_INT)) {
/* Extract method return value */
iVal = sResult.x.iVal;
}
PH7_ClassInstanceUnref((ph7_class_instance *)pObj->x.pOther);
PH7_MemObjRelease(&sResult);
return iVal;
} else if(nType & MEMOBJ_RES) {
return pObj->x.pOther != 0;
}
/* CANT HAPPEN */
return 0;
}
/*
* Return some kind of real value which is the best we can
* do at representing the value that pObj describes as a real.
* If pObj is a real, then the value is exact.If pObj is an
* integer then the integer is promoted to real and that value
* is returned.
* If pObj is a string, then we make an attempt to convert it
3 years ago
* into a real and return that.
* If pObj represents a NULL value, return 0.0
*/
3 years ago
static ph7_real MemObjRealValue(ph7_value *pObj) {
sxi32 nType;
nType = pObj->nType;
if(nType & MEMOBJ_REAL) {
return pObj->x.rVal;
} else if(nType & (MEMOBJ_INT | MEMOBJ_BOOL | MEMOBJ_CHAR)) {
return (ph7_real)pObj->x.iVal;
} else if(nType & MEMOBJ_STRING) {
SyString sString;
ph7_real rVal = 0.0;
3 years ago
SyStringInitFromBuf(&sString, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
if(SyBlobLength(&pObj->sBlob) > 0) {
/* Convert as much as we can */
3 years ago
SyStrToReal(sString.zString, sString.nByte, (void *)&rVal, 0);
}
return rVal;
} else if(nType & (MEMOBJ_CALL | MEMOBJ_NULL | MEMOBJ_VOID)) {
return 0.0;
} else if(nType & MEMOBJ_HASHMAP) {
/* Return the total number of entries in the hashmap */
ph7_hashmap *pMap = (ph7_hashmap *)pObj->x.pOther;
ph7_real n = (ph7_real)pMap->nEntry;
PH7_HashmapUnref(pMap);
return n;
} else if(nType & MEMOBJ_OBJ) {
ph7_value sResult;
ph7_real rVal = 1;
sxi32 rc;
/* Invoke the [__toFloat()] magic method if available [note that this is a symisc extension] */
3 years ago
PH7_MemObjInit(pObj->pVm, &sResult);
rc = MemObjCallClassCastMethod(pObj->pVm, (ph7_class_instance *)pObj->x.pOther,
"__toFloat", sizeof("__toFloat") - 1, &sResult);
if(rc == SXRET_OK && (sResult.nType & MEMOBJ_REAL)) {
/* Extract method return value */
rVal = sResult.x.rVal;
}
PH7_ClassInstanceUnref((ph7_class_instance *)pObj->x.pOther);
PH7_MemObjRelease(&sResult);
return rVal;
} else if(nType & MEMOBJ_RES) {
return (ph7_real)(pObj->x.pOther != 0);
}
/* NOT REACHED */
return 0;
}
3 years ago
/*
* Return the string representation of a given ph7_value.
* This function never fail and always return SXRET_OK.
*/
3 years ago
static sxi32 MemObjStringValue(SyBlob *pOut, ph7_value *pObj, sxu8 bStrictBool) {
if(pObj->nType & MEMOBJ_REAL) {
SyBlobFormat(&(*pOut), "%.15g", pObj->x.rVal);
} else if(pObj->nType & MEMOBJ_INT) {
3 years ago
SyBlobFormat(&(*pOut), "%qd", pObj->x.iVal);
/* %qd (BSD quad) is equivalent to %lld in the libc printf */
} else if(pObj->nType & MEMOBJ_BOOL) {
3 years ago
if(pObj->x.iVal) {
SyBlobAppend(&(*pOut), "TRUE", sizeof("TRUE") - 1);
} else {
if(!bStrictBool) {
SyBlobAppend(&(*pOut), "FALSE", sizeof("FALSE") - 1);
}
}
} else if(pObj->nType & MEMOBJ_CHAR) {
if(pObj->x.iVal > 0) {
SyBlobFormat(&(*pOut), "%c", pObj->x.iVal);
}
} else if(pObj->nType & MEMOBJ_HASHMAP) {
3 years ago
SyBlobAppend(&(*pOut), "Array", sizeof("Array") - 1);
PH7_HashmapUnref((ph7_hashmap *)pObj->x.pOther);
} else if(pObj->nType & MEMOBJ_OBJ) {
ph7_value sResult;
sxi32 rc;
/* Invoke the __toString() method if available */
3 years ago
PH7_MemObjInit(pObj->pVm, &sResult);
rc = MemObjCallClassCastMethod(pObj->pVm, (ph7_class_instance *)pObj->x.pOther,
"__toString", sizeof("__toString") - 1, &sResult);
if(rc == SXRET_OK && (sResult.nType & MEMOBJ_STRING) && SyBlobLength(&sResult.sBlob) > 0) {
/* Expand method return value */
3 years ago
SyBlobDup(&sResult.sBlob, pOut);
} else {
/* Expand "Object" as requested by the PHP language reference manual */
3 years ago
SyBlobAppend(&(*pOut), "Object", sizeof("Object") - 1);
}
PH7_ClassInstanceUnref((ph7_class_instance *)pObj->x.pOther);
PH7_MemObjRelease(&sResult);
} else if(pObj->nType & MEMOBJ_RES) {
3 years ago
SyBlobFormat(&(*pOut), "ResourceID_%#x", pObj->x.pOther);
}
return SXRET_OK;
}
/*
* Return some kind of boolean value which is the best we can do
* at representing the value that pObj describes as a boolean.
* When converting to boolean, the following values are considered FALSE:
* NULL
* the boolean FALSE itself.
* the integer 0 (zero).
* the real 0.0 (zero).
* the empty string,a stream of zero [i.e: "0","00","000",...] and the string
* "false".
3 years ago
* an array with zero elements.
*/
3 years ago
static sxi32 MemObjBooleanValue(ph7_value *pObj) {
sxi32 nType;
nType = pObj->nType;
if(nType & MEMOBJ_REAL) {
return pObj->x.rVal != 0.0 ? 1 : 0;
} else if(nType & (MEMOBJ_INT | MEMOBJ_CHAR)) {
return pObj->x.iVal ? 1 : 0;
} else if(nType & MEMOBJ_STRING) {
SyString sString;
3 years ago
SyStringInitFromBuf(&sString, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
if(sString.nByte == 0) {
/* Empty string */
return 0;
3 years ago
} else if((sString.nByte == sizeof("true") - 1 && SyStrnicmp(sString.zString, "true", sizeof("true") - 1) == 0) ||
(sString.nByte == sizeof("on") - 1 && SyStrnicmp(sString.zString, "on", sizeof("on") - 1) == 0) ||
(sString.nByte == sizeof("yes") - 1 && SyStrnicmp(sString.zString, "yes", sizeof("yes") - 1) == 0)) {
return 1;
} else if(sString.nByte == sizeof("false") - 1 && SyStrnicmp(sString.zString, "false", sizeof("false") - 1) == 0) {
return 0;
3 years ago
} else {
const char *zIn, *zEnd;
zIn = sString.zString;
zEnd = &zIn[sString.nByte];
3 years ago
while(zIn < zEnd && zIn[0] == '0') {
zIn++;
}
return zIn >= zEnd ? 0 : 1;
}
} else if(nType & MEMOBJ_CALL) {
SyString sString;
SyStringInitFromBuf(&sString, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
if(sString.nByte == 0) {
/* Empty string */
return 0;
} else {
/* Something set, return true */
return 1;
}
} else if(nType & (MEMOBJ_NULL | MEMOBJ_VOID)) {
return 0;
} else if(nType & MEMOBJ_HASHMAP) {
ph7_hashmap *pMap = (ph7_hashmap *)pObj->x.pOther;
sxu32 n = pMap->nEntry;
PH7_HashmapUnref(pMap);
return n > 0 ? TRUE : FALSE;
} else if(nType & MEMOBJ_OBJ) {
ph7_value sResult;
sxi32 iVal = 1;
sxi32 rc;
if(!pObj->x.pOther) {
return 0;
}
/* Invoke the __toBool() method if available [note that this is a symisc extension] */
3 years ago
PH7_MemObjInit(pObj->pVm, &sResult);
rc = MemObjCallClassCastMethod(pObj->pVm, (ph7_class_instance *)pObj->x.pOther,
"__toBool", sizeof("__toBool") - 1, &sResult);
if(rc == SXRET_OK && (sResult.nType & (MEMOBJ_INT | MEMOBJ_BOOL))) {
/* Extract method return value */
iVal = (sxi32)(sResult.x.iVal != 0); /* Stupid cc warning -W -Wall -O6 */
}
PH7_ClassInstanceUnref((ph7_class_instance *)pObj->x.pOther);
PH7_MemObjRelease(&sResult);
return iVal;
} else if(nType & MEMOBJ_RES) {
return pObj->x.pOther != 0;
}
/* NOT REACHED */
return 0;
}
/*
* Return the char representation of a given ph7_value.
* This function never fail and always return SXRET_OK.
*/
static ph7_real MemObjCharValue(ph7_value *pObj) {
sxi32 nType;
nType = pObj->nType;
if(nType & (MEMOBJ_CALL | MEMOBJ_REAL | MEMOBJ_HASHMAP | MEMOBJ_RES | MEMOBJ_NULL | MEMOBJ_VOID)) {
return 0;
} else if(nType & MEMOBJ_INT) {
return pObj->x.iVal;
} else if(nType & MEMOBJ_STRING) {
SyString sString;
SyStringInitFromBuf(&sString, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
if(sString.nByte == 0) {
/* Empty string */
return 0;
}
return (int) sString.zString[0];
}
/* NOT REACHED */
return 0;
}
/*
* Checks a ph7_value variable compatibility with nType data type.
*/
PH7_PRIVATE sxi32 PH7_CheckVarCompat(ph7_value *pObj, int nType) {
if(((nType & MEMOBJ_HASHMAP) == 0) && ((pObj->nType & MEMOBJ_HASHMAP) == 0)) {
if(pObj->nType & MEMOBJ_NULL) {
3 years ago
/* Always allow to store a NULL */
return SXRET_OK;
} else if((nType & MEMOBJ_REAL) && (pObj->nType & MEMOBJ_INT)) {
3 years ago
/* Allow to store INT to FLOAT variable */
return SXRET_OK;
} else if((nType & MEMOBJ_CHAR) && (pObj->nType & MEMOBJ_INT)) {
3 years ago
/* Allow to store INT to CHAR variable */
return SXRET_OK;
} else if((nType & MEMOBJ_STRING) && (pObj->nType & MEMOBJ_CHAR)) {
3 years ago
/* Allow to store CHAR to STRING variable */
return SXRET_OK;
} else if((nType & MEMOBJ_CHAR) && (pObj->nType & MEMOBJ_STRING)) {
3 years ago
/* Allow to store STRING to CHAR variable (if not too long) */
int len = SyBlobLength(&pObj->sBlob);
if(len == 0 || len == 1) {
return SXRET_OK;
}
} else if((nType & MEMOBJ_CALL) && (pObj->nType & MEMOBJ_STRING)) {
3 years ago
/* Allow to store STRING to CALLBACK variable */
return SXRET_OK;
}
}
return SXERR_NOMATCH;
}
/*
* Duplicate safely the contents of a ph7_value if source and
* destination are of the compatible data types.
*/
PH7_PRIVATE sxi32 PH7_MemObjSafeStore(ph7_value *pSrc, ph7_value *pDest) {
if(pDest->nType == 0 || pDest->nType == pSrc->nType) {
PH7_MemObjStore(pSrc, pDest);
} else if(pDest->nType & MEMOBJ_MIXED) {
if(pDest->nType & MEMOBJ_HASHMAP) {
/* mixed[] */
if(pSrc->nType & MEMOBJ_HASHMAP) {
PH7_MemObjStore(pSrc, pDest);
pDest->nType |= MEMOBJ_MIXED;
} else if(pSrc->nType & MEMOBJ_NULL) {
PH7_MemObjToHashmap(pSrc);
MemObjSetType(pSrc, pDest->nType);
PH7_MemObjStore(pSrc, pDest);
} else {
return SXERR_NOMATCH;
}
} else {
/* mixed */
if(pSrc->nType == MEMOBJ_NULL) {
MemObjSetType(pDest, MEMOBJ_MIXED | MEMOBJ_VOID);
} else if((pSrc->nType & MEMOBJ_HASHMAP) == 0) {
PH7_MemObjStore(pSrc, pDest);
pDest->nType |= MEMOBJ_MIXED;
} else {
return SXERR_NOMATCH;
}
}
} else if((pDest->nType & MEMOBJ_HASHMAP)) {
/* [] */
if(pSrc->nType & MEMOBJ_NULL) {
PH7_MemObjToHashmap(pSrc);
MemObjSetType(pSrc, pDest->nType);
PH7_MemObjStore(pSrc, pDest);
} else if(pSrc->nType & MEMOBJ_HASHMAP) {
if(PH7_HashmapCast(pSrc, pDest->nType ^ MEMOBJ_HASHMAP) != SXRET_OK) {
return SXERR_NOMATCH;
}
PH7_MemObjStore(pSrc, pDest);
} else {
return SXERR_NOMATCH;
}
} else if(PH7_CheckVarCompat(pSrc, pDest->nType) == SXRET_OK) {
ProcMemObjCast xCast = PH7_MemObjCastMethod(pDest->nType);
xCast(pSrc);
PH7_MemObjStore(pSrc, pDest);
} else {
return SXERR_NOMATCH;
}
return SXRET_OK;
}
/*
* Convert a ph7_value to type integer.Invalidate any prior representations.
*/
3 years ago
PH7_PRIVATE sxi32 PH7_MemObjToInteger(ph7_value *pObj) {
if((pObj->nType & MEMOBJ_INT) == 0) {
/* Preform the conversion */
pObj->x.iVal = MemObjIntValue(&(*pObj));
/* Invalidate any prior representations */
SyBlobRelease(&pObj->sBlob);
3 years ago
MemObjSetType(pObj, MEMOBJ_INT);
}
return SXRET_OK;
}
/*
* Convert a ph7_value to type real (Try to get an integer representation also).
* Invalidate any prior representations
*/
3 years ago
PH7_PRIVATE sxi32 PH7_MemObjToReal(ph7_value *pObj) {
if((pObj->nType & MEMOBJ_REAL) == 0) {
/* Preform the conversion */
pObj->x.rVal = MemObjRealValue(&(*pObj));
/* Invalidate any prior representations */
SyBlobRelease(&pObj->sBlob);
3 years ago
MemObjSetType(pObj, MEMOBJ_REAL);
}
return SXRET_OK;
}
/*
* Convert a ph7_value to type boolean.Invalidate any prior representations.
*/
3 years ago
PH7_PRIVATE sxi32 PH7_MemObjToBool(ph7_value *pObj) {
if((pObj->nType & MEMOBJ_BOOL) == 0) {
/* Preform the conversion */
pObj->x.iVal = MemObjBooleanValue(&(*pObj));
/* Invalidate any prior representations */
SyBlobRelease(&pObj->sBlob);
3 years ago
MemObjSetType(pObj, MEMOBJ_BOOL);
}
return SXRET_OK;
}
PH7_PRIVATE sxi32 PH7_MemObjToChar(ph7_value *pObj) {
if((pObj->nType & MEMOBJ_CHAR) == 0) {
/* Preform the conversion */
pObj->x.iVal = MemObjCharValue(&(*pObj));
/* Invalidate any prior representations */
SyBlobRelease(&pObj->sBlob);
MemObjSetType(pObj, MEMOBJ_CHAR);
}
return SXRET_OK;
}
/*
* Convert a ph7_value to type void.Invalidate any prior representations.
*/
PH7_PRIVATE sxi32 PH7_MemObjToVoid(ph7_value *pObj) {
if((pObj->nType & MEMOBJ_VOID) == 0) {
PH7_MemObjRelease(pObj);
MemObjSetType(pObj, MEMOBJ_VOID);
}
return SXRET_OK;
}
PH7_PRIVATE sxi32 PH7_MemObjToCallback(ph7_value *pObj) {
sxi32 rc = SXRET_OK;
if((pObj->nType & (MEMOBJ_CALL | MEMOBJ_STRING)) == 0) {
SyBlobReset(&pObj->sBlob); /* Reset the internal buffer */
rc = MemObjStringValue(&pObj->sBlob, &(*pObj), TRUE);
}
MemObjSetType(pObj, MEMOBJ_CALL);
return rc;
}
PH7_PRIVATE sxi32 PH7_MemObjToResource(ph7_value *pObj) {
sxi32 rc = SXRET_OK;
if((pObj->nType & MEMOBJ_NULL) == 0) {
PH7_VmThrowError(&(*pObj->pVm), PH7_CTX_WARNING, "Unsafe type casting condition, assuming default value");
}
if((pObj->nType & MEMOBJ_RES) == 0) {
pObj->x.iVal = 0;
}
MemObjSetType(pObj, MEMOBJ_RES);
return rc;
}
/*
* Convert a ph7_value to type string.Prior representations are NOT invalidated.
*/
3 years ago
PH7_PRIVATE sxi32 PH7_MemObjToString(ph7_value *pObj) {
sxi32 rc = SXRET_OK;
if((pObj->nType & MEMOBJ_STRING) == 0) {
if((pObj->nType & MEMOBJ_CALL) == 0) {
/* Perform the conversion */
SyBlobReset(&pObj->sBlob); /* Reset the internal buffer */
rc = MemObjStringValue(&pObj->sBlob, &(*pObj), TRUE);
}
MemObjSetType(pObj, MEMOBJ_STRING);
}
return rc;
}
/*
* Convert a ph7_value to type array.Invalidate any prior representations.
* According to the PHP language reference manual.
* For any of the types: integer, float, string, boolean converting a value
3 years ago
* to an array results in an array with a single element with index zero
* and the value of the scalar which was converted.
*/
3 years ago
PH7_PRIVATE sxi32 PH7_MemObjToHashmap(ph7_value *pObj) {
if((pObj->nType & MEMOBJ_HASHMAP) == 0) {
ph7_hashmap *pMap;
/* Allocate a new hashmap instance */
3 years ago
pMap = PH7_NewHashmap(pObj->pVm, 0, 0);
if(pMap == 0) {
return SXERR_MEM;
}
if((pObj->nType & (MEMOBJ_NULL | MEMOBJ_RES)) == 0) {
3 years ago
/*
* According to the PHP language reference manual.
* For any of the types: integer, float, string, boolean converting a value
3 years ago
* to an array results in an array with a single element with index zero
* and the value of the scalar which was converted.
*/
if(pObj->nType & MEMOBJ_OBJ) {
/* Object cast */
3 years ago
PH7_ClassInstanceToHashmap((ph7_class_instance *)pObj->x.pOther, pMap);
} else {
/* Insert a single element */
3 years ago
PH7_HashmapInsert(pMap, 0/* Automatic index assign */, &(*pObj));
}
SyBlobRelease(&pObj->sBlob);
}
/* Invalidate any prior representation */
3 years ago
MemObjSetType(pObj, MEMOBJ_HASHMAP);
pObj->x.pOther = pMap;
}
return SXRET_OK;
}
/*
* Convert a ph7_value to type object.Invalidate any prior representations.
* The new object is instantiated from the builtin stdClass().
* The stdClass() class have a single attribute which is '$value'. This attribute
* hold a copy of the converted ph7_value.
* The internal of the stdClass is as follows:
* class stdClass{
* public $value;
* public function __toInt(){ return (int)$this->value; }
* public function __toBool(){ return (bool)$this->value; }
* public function __toFloat(){ return (float)$this->value; }
* public function __toString(){ return (string)$this->value; }
* function __construct($v){ $this->value = $v; }"
* }
* Refer to the official documentation for more information.
*/
3 years ago
PH7_PRIVATE sxi32 PH7_MemObjToObject(ph7_value *pObj) {
if(pObj->nType & MEMOBJ_NULL) {
/* Invalidate any prior representation */
PH7_MemObjRelease(pObj);
/* Typecast the value */
MemObjSetType(pObj, MEMOBJ_OBJ);
} else if((pObj->nType & MEMOBJ_OBJ) == 0) {
ph7_class_instance *pStd;
ph7_class_method *pCons;
ph7_class *pClass;
ph7_vm *pVm;
/* Point to the underlying VM */
pVm = pObj->pVm;
/* Point to the stdClass() */
3 years ago
pClass = PH7_VmExtractClass(pVm, "stdClass", sizeof("stdClass") - 1, 0, 0);
if(pClass == 0) {
/* Can't happen,load null instead */
PH7_MemObjRelease(pObj);
return SXRET_OK;
}
/* Instantiate a new stdClass() object */
3 years ago
pStd = PH7_NewClassInstance(pVm, pClass);
if(pStd == 0) {
/* Out of memory */
PH7_MemObjRelease(pObj);
return SXRET_OK;
}
/* Check if a constructor is available */
3 years ago
pCons = PH7_ClassExtractMethod(pClass, "__construct", sizeof("__construct") - 1);
if(pCons) {
ph7_value *apArg[2];
/* Invoke the constructor with one argument */
apArg[0] = pObj;
3 years ago
PH7_VmCallClassMethod(pVm, pStd, pCons, 0, 1, apArg);
if(pStd->iRef < 1) {
pStd->iRef = 1;
}
}
/* Invalidate any prior representation */
PH7_MemObjRelease(pObj);
/* Save the new instance */
pObj->x.pOther = pStd;
3 years ago
MemObjSetType(pObj, MEMOBJ_OBJ);
}
return SXRET_OK;
}
/*
3 years ago
* Return a pointer to the appropriate convertion method associated
* with the given type.
* Note on type juggling.
* According to the PHP language reference manual
* PHP does not require (or support) explicit type definition in variable
* declaration; a variable's type is determined by the context in which
3 years ago
* the variable is used. That is to say, if a string value is assigned
* to variable $var, $var becomes a string. If an integer value is then
3 years ago
* assigned to $var, it becomes an integer.
*/
PH7_PRIVATE ProcMemObjCast PH7_MemObjCastMethod(sxi32 nType) {
if(nType & MEMOBJ_STRING) {
return PH7_MemObjToString;
} else if(nType & MEMOBJ_INT) {
return PH7_MemObjToInteger;
} else if(nType & MEMOBJ_REAL) {
return PH7_MemObjToReal;
} else if(nType & MEMOBJ_BOOL) {
return PH7_MemObjToBool;
} else if(nType & MEMOBJ_CHAR) {
return PH7_MemObjToChar;
} else if(nType & MEMOBJ_OBJ) {
return PH7_MemObjToObject;
} else if(nType & MEMOBJ_CALL) {
return PH7_MemObjToCallback;
} else if(nType & MEMOBJ_RES) {
return PH7_MemObjToResource;
} else if(nType & MEMOBJ_VOID) {
return PH7_MemObjToVoid;
}
/* Release the variable */
return PH7_MemObjRelease;
}
/*
* Check whether the ph7_value is numeric [i.e: int/float/bool] or looks
* like a numeric number [i.e: if the ph7_value is of type string.].
* Return TRUE if numeric.FALSE otherwise.
*/
3 years ago
PH7_PRIVATE sxi32 PH7_MemObjIsNumeric(ph7_value *pObj) {
if(pObj->nType & (MEMOBJ_INT | MEMOBJ_REAL)) {
return TRUE;
}
return FALSE;
}
/*
* Convert a ph7_value so that it has types MEMOBJ_REAL or MEMOBJ_INT
* or both.
* Invalidate any prior representations. Every effort is made to force
3 years ago
* the conversion, even if the input is a string that does not look
* completely like a number.Convert as much of the string as we can
* and ignore the rest.
*/
3 years ago
PH7_PRIVATE sxi32 PH7_MemObjToNumeric(ph7_value *pObj) {
if(pObj->nType & (MEMOBJ_INT | MEMOBJ_REAL | MEMOBJ_BOOL | MEMOBJ_NULL)) {
if(pObj->nType & (MEMOBJ_BOOL | MEMOBJ_NULL | MEMOBJ_VOID)) {
if(pObj->nType & (MEMOBJ_CALL | MEMOBJ_NULL | MEMOBJ_VOID)) {
pObj->x.iVal = 0;
}
3 years ago
MemObjSetType(pObj, MEMOBJ_INT);
}
/* Already numeric */
return SXRET_OK;
}
if(pObj->nType & MEMOBJ_STRING) {
sxi32 rc = SXERR_INVALID;
sxu8 bReal = FALSE;
SyString sString;
3 years ago
SyStringInitFromBuf(&sString, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
/* Check if the given string looks like a numeric number */
3 years ago
if(sString.nByte > 0) {
rc = SyStrIsNumeric(sString.zString, sString.nByte, &bReal, 0);
}
3 years ago
if(bReal) {
PH7_MemObjToReal(&(*pObj));
3 years ago
} else {
if(rc != SXRET_OK) {
/* The input does not look at all like a number,set the value to 0 */
pObj->x.iVal = 0;
3 years ago
} else {
/* Convert as much as we can */
pObj->x.iVal = MemObjStringToInt(&(*pObj));
}
3 years ago
MemObjSetType(pObj, MEMOBJ_INT);
SyBlobRelease(&pObj->sBlob);
}
} else if(pObj->nType & (MEMOBJ_OBJ | MEMOBJ_HASHMAP | MEMOBJ_RES)) {
PH7_MemObjToInteger(pObj);
3 years ago
} else {
/* Perform a blind cast */
PH7_MemObjToReal(&(*pObj));
}
return SXRET_OK;
}
/*
* Initialize a ph7_value to the null type.
*/
3 years ago
PH7_PRIVATE sxi32 PH7_MemObjInit(ph7_vm *pVm, ph7_value *pObj) {
/* Zero the structure */
3 years ago
SyZero(pObj, sizeof(ph7_value));
/* Initialize fields */
pObj->pVm = pVm;
3 years ago
SyBlobInit(&pObj->sBlob, &pVm->sAllocator);
/* Set the NULL type */
pObj->nType = MEMOBJ_NULL;
return SXRET_OK;
}
/*
* Initialize a ph7_value to the integer type.
*/
3 years ago
PH7_PRIVATE sxi32 PH7_MemObjInitFromInt(ph7_vm *pVm, ph7_value *pObj, sxi64 iVal) {
/* Zero the structure */
3 years ago
SyZero(pObj, sizeof(ph7_value));
/* Initialize fields */
pObj->pVm = pVm;
3 years ago
SyBlobInit(&pObj->sBlob, &pVm->sAllocator);
/* Set the desired type */
pObj->x.iVal = iVal;
pObj->nType = MEMOBJ_INT;
return SXRET_OK;
}
/*
* Initialize a ph7_value to the boolean type.
*/
3 years ago
PH7_PRIVATE sxi32 PH7_MemObjInitFromBool(ph7_vm *pVm, ph7_value *pObj, sxi32 iVal) {
/* Zero the structure */
3 years ago
SyZero(pObj, sizeof(ph7_value));
/* Initialize fields */
pObj->pVm = pVm;
3 years ago
SyBlobInit(&pObj->sBlob, &pVm->sAllocator);
/* Set the desired type */
pObj->x.iVal = iVal ? 1 : 0;
pObj->nType = MEMOBJ_BOOL;
return SXRET_OK;
}
/*
* Initialize a ph7_value to the real type.
*/
3 years ago
PH7_PRIVATE sxi32 PH7_MemObjInitFromReal(ph7_vm *pVm, ph7_value *pObj, ph7_real rVal) {
/* Zero the structure */
3 years ago
SyZero(pObj, sizeof(ph7_value));
/* Initialize fields */
pObj->pVm = pVm;
3 years ago
SyBlobInit(&pObj->sBlob, &pVm->sAllocator);
/* Set the desired type */
pObj->x.rVal = rVal;
pObj->nType = MEMOBJ_REAL;
return SXRET_OK;
}
/*
* Initialize a ph7_value to the void type.
*/
PH7_PRIVATE sxi32 PH7_MemObjInitFromVoid(ph7_vm *pVm, ph7_value *pObj, ph7_real rVal) {