Typehinting merge #50

Merged
belliash merged 298 commits from typehinting into master 2019-04-17 11:27:52 +02:00
98 changed files with 3021 additions and 2164 deletions

View File

@ -7,4 +7,4 @@ pipeline:
- make install
step: test
commands:
- make test
- make tests

6
.vscode/tasks.json vendored
View File

@ -4,7 +4,7 @@
"version": "2.0.0",
"tasks": [
{
"label": "Build P# Interpreter",
"label": "Build AerScript Interpreter",
"type": "shell",
"command": "make",
"group": {
@ -16,7 +16,7 @@
}
},
{
"label": "Clean P# Interpreter",
"label": "Clean AerScript Interpreter",
"type": "shell",
"command": "make",
"args": [
@ -31,7 +31,7 @@
}
},
{
"label": "Style P# Code",
"label": "Style AerScript Interpreter Code",
"type": "shell",
"command": "make",
"args": [

View File

@ -117,7 +117,7 @@ TESTS := $(subst .$(TEST_EXT),.test,$(wildcard $(TEST_DIR)/*.$(TEST_EXT)))
.SUFFIXES:
.PHONY: clean debug install release style test
.PHONY: clean debug install release style tests
debug: export CFLAGS := $(CFLAGS) $(DCFLAGS)
debug: engine sapi modules
@ -183,4 +183,4 @@ install: engine modules sapi
style:
astyle $(ASTYLE_FLAGS) --recursive ./*.c,*.h
test: $(TESTS)
tests: $(TESTS)

2
TODO Normal file
View File

@ -0,0 +1,2 @@
TODO list for typehinting branch.
Below list contains things that should be changed/fixed/implemented.

View File

@ -1777,12 +1777,18 @@ int ph7_value_bool(ph7_value *pVal, int iBool) {
return PH7_OK;
}
/*
* [CAPIREF: ph7_value_null()]
* [CAPIREF: ph7_value_char()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_null(ph7_value *pVal) {
/* Invalidate any prior representation and set the NULL flag */
int ph7_value_char(ph7_value *pVal, int cValue) {
/* Invalidate any prior representation */
PH7_MemObjRelease(pVal);
if(cValue >= 0 && cValue <= 255) {
pVal->x.iVal = cValue;
} else {
pVal->x.iVal = 0;
}
MemObjSetType(pVal, MEMOBJ_CHAR);
return PH7_OK;
}
/*
@ -1796,6 +1802,16 @@ int ph7_value_double(ph7_value *pVal, double Value) {
MemObjSetType(pVal, MEMOBJ_REAL);
return PH7_OK;
}
/*
* [CAPIREF: ph7_value_void()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_void(ph7_value *pVal) {
/* Invalidate any prior representation */
PH7_MemObjRelease(pVal);
MemObjSetType(pVal, MEMOBJ_VOID);
return PH7_OK;
}
/*
* [CAPIREF: ph7_value_string()]
* Please refer to the official documentation for function purpose and expected parameters.
@ -1882,6 +1898,20 @@ int ph7_value_is_float(ph7_value *pVal) {
int ph7_value_is_bool(ph7_value *pVal) {
return (pVal->iFlags & MEMOBJ_BOOL) ? TRUE : FALSE;
}
/*
* [CAPIREF: ph7_value_is_char()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_is_char(ph7_value *pVal) {
return (pVal->iFlags & MEMOBJ_CHAR) ? TRUE : FALSE;
}
/*
* [CAPIREF: ph7_value_is_void()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_is_void(ph7_value *pVal) {
return (pVal->iFlags & MEMOBJ_VOID) ? TRUE : FALSE;
}
/*
* [CAPIREF: ph7_value_is_string()]
* Please refer to the official documentation for function purpose and expected parameters.
@ -1889,13 +1919,6 @@ int ph7_value_is_bool(ph7_value *pVal) {
int ph7_value_is_string(ph7_value *pVal) {
return (pVal->iFlags & MEMOBJ_STRING) ? TRUE : FALSE;
}
/*
* [CAPIREF: ph7_value_is_null()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_is_null(ph7_value *pVal) {
return (pVal->iFlags & MEMOBJ_NULL) ? TRUE : FALSE;
}
/*
* [CAPIREF: ph7_value_is_numeric()]
* Please refer to the official documentation for function purpose and expected parameters.
@ -1914,6 +1937,13 @@ int ph7_value_is_callable(ph7_value *pVal) {
rc = PH7_VmIsCallable(pVal->pVm, pVal, FALSE);
return rc;
}
/*
* [CAPIREF: ph7_value_is_callback()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_is_callback(ph7_value *pVal) {
return (pVal->iFlags & MEMOBJ_CALL) ? TRUE : FALSE;
}
/*
* [CAPIREF: ph7_value_is_scalar()]
* Please refer to the official documentation for function purpose and expected parameters.
@ -1942,12 +1972,3 @@ int ph7_value_is_object(ph7_value *pVal) {
int ph7_value_is_resource(ph7_value *pVal) {
return (pVal->iFlags & MEMOBJ_RES) ? TRUE : FALSE;
}
/*
* [CAPIREF: ph7_value_is_empty()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_is_empty(ph7_value *pVal) {
int rc;
rc = PH7_MemObjIsEmpty(pVal);
return rc;
}

View File

@ -39,10 +39,42 @@ static int PH7_builtin_is_bool(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_result_bool(pCtx, res);
return PH7_OK;
}
/*
* bool is_callback($var)
* Finds out whether a variable is a callback.
* Parameters
* $var: The variable being evaluated.
* Return
* TRUE if var is a callback. False otherwise.
*/
static int PH7_builtin_is_callback(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int res = 0; /* Assume false by default */
if(nArg > 0) {
res = ph7_value_is_callback(apArg[0]);
}
/* Query result */
ph7_result_bool(pCtx, res);
return PH7_OK;
}
/*
* bool is_char($var)
* Finds out whether a variable is a character.
* Parameters
* $var: The variable being evaluated.
* Return
* TRUE if var is a character. False otherwise.
*/
static int PH7_builtin_is_char(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int res = 0; /* Assume false by default */
if(nArg > 0) {
res = ph7_value_is_char(apArg[0]);
}
/* Query result */
ph7_result_bool(pCtx, res);
return PH7_OK;
}
/*
* bool is_float($var)
* bool is_real($var)
* bool is_double($var)
* Finds out whether a variable is a float.
* Parameters
* $var: The variable being evaluated.
@ -60,8 +92,6 @@ static int PH7_builtin_is_float(ph7_context *pCtx, int nArg, ph7_value **apArg)
}
/*
* bool is_int($var)
* bool is_integer($var)
* bool is_long($var)
* Finds out whether a variable is an integer.
* Parameters
* $var: The variable being evaluated.
@ -95,17 +125,17 @@ static int PH7_builtin_is_string(ph7_context *pCtx, int nArg, ph7_value **apArg)
return PH7_OK;
}
/*
* bool is_null($var)
* Finds out whether a variable is NULL.
* bool is_void($var)
* Finds out whether a variable is a void.
* Parameters
* $var: The variable being evaluated.
* Return
* TRUE if var is NULL. False otherwise.
* TRUE if var is void. False otherwise.
*/
static int PH7_builtin_is_null(ph7_context *pCtx, int nArg, ph7_value **apArg) {
static int PH7_builtin_is_void(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int res = 0; /* Assume false by default */
if(nArg > 0) {
res = ph7_value_is_null(apArg[0]);
res = ph7_value_is_void(apArg[0]);
}
/* Query result */
ph7_result_bool(pCtx, res);
@ -128,23 +158,6 @@ static int PH7_builtin_is_numeric(ph7_context *pCtx, int nArg, ph7_value **apArg
ph7_result_bool(pCtx, res);
return PH7_OK;
}
/*
* bool is_scalar($var)
* Find out whether a variable is a scalar.
* Parameters
* $var: The variable being evaluated.
* Return
* True if var is scalar. False otherwise.
*/
static int PH7_builtin_is_scalar(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int res = 0; /* Assume false by default */
if(nArg > 0) {
res = ph7_value_is_scalar(apArg[0]);
}
/* Query result */
ph7_result_bool(pCtx, res);
return PH7_OK;
}
/*
* bool is_array($var)
* Find out whether a variable is an array.
@ -195,83 +208,6 @@ static int PH7_builtin_is_resource(ph7_context *pCtx, int nArg, ph7_value **apAr
ph7_result_bool(pCtx, res);
return PH7_OK;
}
/*
* float floatval($var)
* Get float value of a variable.
* Parameter
* $var: The variable being processed.
* Return
* the float value of a variable.
*/
static int PH7_builtin_floatval(ph7_context *pCtx, int nArg, ph7_value **apArg) {
if(nArg < 1) {
/* return 0.0 */
ph7_result_double(pCtx, 0);
} else {
double dval;
/* Perform the cast */
dval = ph7_value_to_double(apArg[0]);
ph7_result_double(pCtx, dval);
}
return PH7_OK;
}
/*
* int intval($var)
* Get integer value of a variable.
* Parameter
* $var: The variable being processed.
* Return
* the int value of a variable.
*/
static int PH7_builtin_intval(ph7_context *pCtx, int nArg, ph7_value **apArg) {
if(nArg < 1) {
/* return 0 */
ph7_result_int(pCtx, 0);
} else {
sxi64 iVal;
/* Perform the cast */
iVal = ph7_value_to_int64(apArg[0]);
ph7_result_int64(pCtx, iVal);
}
return PH7_OK;
}
/*
* string strval($var)
* Get the string representation of a variable.
* Parameter
* $var: The variable being processed.
* Return
* the string value of a variable.
*/
static int PH7_builtin_strval(ph7_context *pCtx, int nArg, ph7_value **apArg) {
if(nArg < 1) {
/* return NULL */
ph7_result_null(pCtx);
} else {
const char *zVal;
int iLen = 0; /* cc -O6 warning */
/* Perform the cast */
zVal = ph7_value_to_string(apArg[0], &iLen);
ph7_result_string(pCtx, zVal, iLen);
}
return PH7_OK;
}
/*
* bool empty($var)
* Determine whether a variable is empty.
* Parameters
* $var: The variable being checked.
* Return
* 0 if var has a non-empty and non-zero value.1 otherwise.
*/
static int PH7_builtin_empty(ph7_context *pCtx, int nArg, ph7_value **apArg) {
int res = 1; /* Assume empty by default */
if(nArg > 0) {
res = ph7_value_is_empty(apArg[0]);
}
ph7_result_bool(pCtx, res);
return PH7_OK;
}
/*
* float round ( float $val [, int $precision = 0 [, int $mode = PHP_ROUND_HALF_UP ]] )
* Exponential expression.
@ -307,7 +243,7 @@ static int PH7_builtin_round(ph7_context *pCtx, int nArg, ph7_value **apArg) {
r = ph7_value_to_double(apArg[0]);
/* If Y==0 and X will fit in a 64-bit int,
* handle the rounding directly.Otherwise
* use our own cutsom printf [i.e:SyBufferFormat()].
* use our own custom printf [i.e:SyBufferFormat()].
*/
if(n == 0 && r >= 0 && r < LARGEST_INT64 - 1) {
r = (double)((ph7_int64)(r + 0.5));
@ -4330,8 +4266,6 @@ static int PH7_builtin_str_getcsv(ph7_context *pCtx, int nArg, ph7_value **apArg
pArray = ph7_context_new_array(pCtx);
if(pArray == 0) {
PH7_VmMemoryError(pCtx->pVm);
ph7_result_null(pCtx);
return PH7_OK;
}
/* Parse the raw input */
PH7_ProcessCsv(zInput, nLen, delim, encl, escape, PH7_CsvConsumer, pArray);
@ -5189,7 +5123,7 @@ static int PH7_builtin_strtok(ph7_context *pCtx, int nArg, ph7_value **apArg) {
pAux = (strtok_aux_data *)ph7_context_peek_aux_data(pCtx);
if(pAux == 0) {
/* No aux data,return FALSE */
ph7_result_bool(pCtx, 0);
ph7_result_string(pCtx, "", 0);
return PH7_OK;
}
nMasklen = 0;
@ -5203,7 +5137,7 @@ static int PH7_builtin_strtok(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_context_free_chunk(pCtx, (void *)pAux->zDup);
ph7_context_free_chunk(pCtx, pAux);
(void)ph7_context_pop_aux_data(pCtx);
ph7_result_bool(pCtx, 0);
ph7_result_string(pCtx, "", 0);
return PH7_OK;
}
/* Extract the token */
@ -5213,7 +5147,7 @@ static int PH7_builtin_strtok(ph7_context *pCtx, int nArg, ph7_value **apArg) {
ph7_context_free_chunk(pCtx, (void *)pAux->zDup);
ph7_context_free_chunk(pCtx, pAux);
(void)ph7_context_pop_aux_data(pCtx);
ph7_result_bool(pCtx, 0);
ph7_result_string(pCtx, "", 0);
} else {
/* Return the extracted token */
ph7_result_string(pCtx, sToken.zString, (int)sToken.nByte);
@ -5226,7 +5160,7 @@ static int PH7_builtin_strtok(ph7_context *pCtx, int nArg, ph7_value **apArg) {
zCur = zInput = ph7_value_to_string(apArg[0], &nLen);
if(nLen < 1) {
/* Empty input,return FALSE */
ph7_result_bool(pCtx, 0);
ph7_result_string(pCtx, "", 0);
return PH7_OK;
}
/* Extract the mask */
@ -5242,7 +5176,7 @@ static int PH7_builtin_strtok(ph7_context *pCtx, int nArg, ph7_value **apArg) {
rc = ExtractToken(&zInput, &zInput[nLen], zMask, nMasklen, &sToken);
if(rc != SXRET_OK) {
/* Empty input */
ph7_result_bool(pCtx, 0);
ph7_result_string(pCtx, "", 0);
return PH7_OK;
} else {
/* Return the extracted token */
@ -5501,9 +5435,8 @@ static int StrReplaceWalker(ph7_value *pKey, ph7_value *pData, void *pUserData)
TRUE /* Release the chunk automatically,upon this context is destroyed */
);
if(zDup == 0) {
/* Ignore any memory failure problem */
/* Memory failure problem */
PH7_VmMemoryError(pRep->pCtx->pVm);
return PH7_OK;
}
SyMemcpy(zIn, zDup, (sxu32)nByte);
/* Save the chunk */
@ -5777,9 +5710,6 @@ PH7_PRIVATE sxi32 PH7_ParseIniString(ph7_context *pCtx, const char *zIn, sxu32 n
if(pArray == 0 || pWorker == 0 || pValue == 0) {
/* Out of memory */
PH7_VmMemoryError(pCtx->pVm);
/* Return FALSE */
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
SyHashInit(&sHash, &pCtx->pVm->sAllocator, 0, 0);
pCur = pArray;
@ -7473,20 +7403,17 @@ static int PH7_builtin_urldecode(ph7_context *pCtx, int nArg, ph7_value **apArg)
/* Table of the built-in functions */
static const ph7_builtin_func aBuiltInFunc[] = {
/* Variable handling functions */
{ "is_array", PH7_builtin_is_array },
{ "is_bool", PH7_builtin_is_bool },
{ "is_callback", PH7_builtin_is_callback },
{ "is_char", PH7_builtin_is_char },
{ "is_float", PH7_builtin_is_float },
{ "is_int", PH7_builtin_is_int },
{ "is_string", PH7_builtin_is_string },
{ "is_null", PH7_builtin_is_null },
{ "is_numeric", PH7_builtin_is_numeric },
{ "is_scalar", PH7_builtin_is_scalar },
{ "is_array", PH7_builtin_is_array },
{ "is_object", PH7_builtin_is_object },
{ "is_resource", PH7_builtin_is_resource },
{ "floatval", PH7_builtin_floatval },
{ "intval", PH7_builtin_intval },
{ "stringval", PH7_builtin_strval },
{ "empty", PH7_builtin_empty },
{ "is_string", PH7_builtin_is_string },
{ "is_void", PH7_builtin_is_void },
{ "is_numeric", PH7_builtin_is_numeric },
{ "round", PH7_builtin_round },
{ "dechex", PH7_builtin_dechex },
{ "decoct", PH7_builtin_decoct },

File diff suppressed because it is too large Load Diff

View File

@ -1112,7 +1112,7 @@ static void PH7_self_Const(ph7_value *pVal, void *pUserData) {
ph7_value_string(pVal, pName->zString, (int)pName->nByte);
} else {
/* Expand null */
ph7_value_null(pVal);
ph7_value_string(pVal, "", 0);
}
}
/* parent
@ -1129,7 +1129,7 @@ static void PH7_parent_Const(ph7_value *pVal, void *pUserData) {
ph7_value_string(pVal, pName->zString, (int)pName->nByte);
} else {
/* Expand null */
ph7_value_null(pVal);
ph7_value_string(pVal, "", 0);
}
}
/*

View File

@ -16,10 +16,6 @@
/* Allowed node types */
#define HASHMAP_INT_NODE 1 /* Node with an int [i.e: 64-bit integer] key */
#define HASHMAP_BLOB_NODE 2 /* Node with a string/BLOB key */
/* Node control flags */
#define HASHMAP_NODE_FOREIGN_OBJ 0x001 /* Node hold a reference to a foreign ph7_value
* [i.e: array(&var)/$a[] =& $var ]
*/
/*
* Default hash function for int [i.e; 64-bit integer] keys.
*/
@ -193,9 +189,7 @@ PH7_PRIVATE void PH7_HashmapUnlinkNode(ph7_hashmap_node *pNode, int bRestore) {
/* Remove the ph7_value associated with this node from the reference table */
PH7_VmRefObjRemove(pVm, pNode->nValIdx, 0, pNode);
/* Restore to the freelist */
if((pNode->iFlags & HASHMAP_NODE_FOREIGN_OBJ) == 0) {
PH7_VmUnsetMemObj(pVm, pNode->nValIdx, FALSE);
}
PH7_VmUnsetMemObj(pVm, pNode->nValIdx, FALSE);
}
if(pNode->iType == HASHMAP_BLOB_NODE) {
SyBlobRelease(&pNode->xKey.sKey);
@ -271,26 +265,22 @@ static sxi32 HashmapGrowBucket(ph7_hashmap *pMap) {
* Insert a 64-bit integer key and it's associated value (if any) in the given
* hashmap.
*/
static sxi32 HashmapInsertIntKey(ph7_hashmap *pMap, sxi64 iKey, ph7_value *pValue, sxu32 nRefIdx, int isForeign) {
static sxi32 HashmapInsertIntKey(ph7_hashmap *pMap, sxi64 iKey, ph7_value *pValue, sxu32 nRefIdx) {
ph7_hashmap_node *pNode;
sxu32 nIdx;
sxu32 nHash;
sxi32 rc;
if(!isForeign) {
ph7_value *pObj;
/* Reserve a ph7_value for the value */
pObj = PH7_ReserveMemObj(pMap->pVm);
if(pObj == 0) {
return SXERR_MEM;
}
if(pValue) {
/* Duplicate the value */
PH7_MemObjStore(pValue, pObj);
}
nIdx = pObj->nIdx;
} else {
nIdx = nRefIdx;
ph7_value *pObj;
/* Reserve a ph7_value for the value */
pObj = PH7_ReserveMemObj(pMap->pVm);
if(pObj == 0) {
return SXERR_MEM;
}
if(pValue) {
/* Duplicate the value */
PH7_MemObjStore(pValue, pObj);
}
nIdx = pObj->nIdx;
/* Hash the key */
nHash = pMap->xIntHash(iKey);
/* Allocate a new int node */
@ -298,10 +288,6 @@ static sxi32 HashmapInsertIntKey(ph7_hashmap *pMap, sxi64 iKey, ph7_value *pValu
if(pNode == 0) {
return SXERR_MEM;
}
if(isForeign) {
/* Mark as a foregin entry */
pNode->iFlags |= HASHMAP_NODE_FOREIGN_OBJ;
}
/* Make sure the bucket is big enough to hold the new entry */
rc = HashmapGrowBucket(&(*pMap));
if(rc != SXRET_OK) {
@ -319,26 +305,22 @@ static sxi32 HashmapInsertIntKey(ph7_hashmap *pMap, sxi64 iKey, ph7_value *pValu
* Insert a BLOB key and it's associated value (if any) in the given
* hashmap.
*/
static sxi32 HashmapInsertBlobKey(ph7_hashmap *pMap, const void *pKey, sxu32 nKeyLen, ph7_value *pValue, sxu32 nRefIdx, int isForeign) {
static sxi32 HashmapInsertBlobKey(ph7_hashmap *pMap, const void *pKey, sxu32 nKeyLen, ph7_value *pValue, sxu32 nRefIdx) {
ph7_hashmap_node *pNode;
sxu32 nHash;
sxu32 nIdx;
sxi32 rc;
if(!isForeign) {
ph7_value *pObj;
/* Reserve a ph7_value for the value */
pObj = PH7_ReserveMemObj(pMap->pVm);
if(pObj == 0) {
return SXERR_MEM;
}
if(pValue) {
/* Duplicate the value */
PH7_MemObjStore(pValue, pObj);
}
nIdx = pObj->nIdx;
} else {
nIdx = nRefIdx;
ph7_value *pObj;
/* Reserve a ph7_value for the value */
pObj = PH7_ReserveMemObj(pMap->pVm);
if(pObj == 0) {
return SXERR_MEM;
}
if(pValue) {
/* Duplicate the value */
PH7_MemObjStore(pValue, pObj);
}
nIdx = pObj->nIdx;
/* Hash the key */
nHash = pMap->xBlobHash(pKey, nKeyLen);
/* Allocate a new blob node */
@ -346,10 +328,6 @@ static sxi32 HashmapInsertBlobKey(ph7_hashmap *pMap, const void *pKey, sxu32 nKe
if(pNode == 0) {
return SXERR_MEM;
}
if(isForeign) {
/* Mark as a foregin entry */
pNode->iFlags |= HASHMAP_NODE_FOREIGN_OBJ;
}
/* Make sure the bucket is big enough to hold the new entry */
rc = HashmapGrowBucket(&(*pMap));
if(rc != SXRET_OK) {
@ -546,14 +524,14 @@ static sxi32 HashmapInsert(
if(pVal) {
PH7_MemObjStore(pVal, pElem);
} else {
/* Nullify the entry */
PH7_MemObjToNull(pElem);
/* Release the entry */
PH7_MemObjRelease(pElem);
}
}
return SXRET_OK;
}
/* Perform a blob-key insertion */
rc = HashmapInsertBlobKey(&(*pMap), SyBlobData(&pKey->sBlob), SyBlobLength(&pKey->sBlob), &(*pVal), 0, FALSE);
rc = HashmapInsertBlobKey(&(*pMap), SyBlobData(&pKey->sBlob), SyBlobLength(&pKey->sBlob), &(*pVal), 0);
return rc;
}
IntKey:
@ -570,14 +548,14 @@ IntKey:
if(pVal) {
PH7_MemObjStore(pVal, pElem);
} else {
/* Nullify the entry */
PH7_MemObjToNull(pElem);
/* Release the entry */
PH7_MemObjRelease(pElem);
}
}
return SXRET_OK;
}
/* Perform a 64-bit-int-key insertion */
rc = HashmapInsertIntKey(&(*pMap), pKey->x.iVal, &(*pVal), 0, FALSE);
rc = HashmapInsertIntKey(&(*pMap), pKey->x.iVal, &(*pVal), 0);
if(rc == SXRET_OK) {
if(pKey->x.iVal >= pMap->iNextIdx) {
/* Increment the automatic index */
@ -590,102 +568,7 @@ IntKey:
}
} else {
/* Assign an automatic index */
rc = HashmapInsertIntKey(&(*pMap), pMap->iNextIdx, &(*pVal), 0, FALSE);
if(rc == SXRET_OK) {
++pMap->iNextIdx;
}
}
/* Insertion result */
return rc;
}
/*
* Insert a given key and it's associated value (foreign index) in the given
* hashmap.
* This is insertion by reference so be careful to mark the node
* with the HASHMAP_NODE_FOREIGN_OBJ flag being set.
* The insertion by reference is triggered when the following
* expression is encountered.
* $var = 10;
* $a = array(&var);
* OR
* $a[] =& $var;
* That is,$var is a foreign ph7_value and the $a array have no control
* over it's contents.
* Note that the node that hold the foreign ph7_value is automatically
* removed when the foreign ph7_value is unset.
* Example:
* $var = 10;
* $a[] =& $var;
* echo count($a).PHP_EOL; //1
* //Unset the foreign ph7_value now
* unset($var);
* echo count($a); //0
* Note that this is a PH7 eXtension.
* Refer to the official documentation for more information.
* If a node with the given key already exists in the database
* then this function overwrite the old value.
*/
static sxi32 HashmapInsertByRef(
ph7_hashmap *pMap, /* Target hashmap */
ph7_value *pKey, /* Lookup key */
sxu32 nRefIdx /* Foreign ph7_value index */
) {
ph7_hashmap_node *pNode = 0;
sxi32 rc = SXRET_OK;
if(pKey && pKey->iFlags & (MEMOBJ_STRING | MEMOBJ_HASHMAP | MEMOBJ_OBJ | MEMOBJ_RES)) {
if((pKey->iFlags & MEMOBJ_STRING) == 0) {
/* Force a string cast */
PH7_MemObjToString(&(*pKey));
}
if(SyBlobLength(&pKey->sBlob) < 1 || HashmapIsIntKey(&pKey->sBlob)) {
if(SyBlobLength(&pKey->sBlob) < 1) {
/* Automatic index assign */
pKey = 0;
}
goto IntKey;
}
if(SXRET_OK == HashmapLookupBlobKey(&(*pMap), SyBlobData(&pKey->sBlob),
SyBlobLength(&pKey->sBlob), &pNode)) {
/* Overwrite */
PH7_VmRefObjRemove(pMap->pVm, pNode->nValIdx, 0, pNode);
pNode->nValIdx = nRefIdx;
/* Install in the reference table */
PH7_VmRefObjInstall(pMap->pVm, nRefIdx, 0, pNode, 0);
return SXRET_OK;
}
/* Perform a blob-key insertion */
rc = HashmapInsertBlobKey(&(*pMap), SyBlobData(&pKey->sBlob), SyBlobLength(&pKey->sBlob), 0, nRefIdx, TRUE);
return rc;
}
IntKey:
if(pKey) {
if((pKey->iFlags & MEMOBJ_INT) == 0) {
/* Force an integer cast */
PH7_MemObjToInteger(pKey);
}
if(SXRET_OK == HashmapLookupIntKey(&(*pMap), pKey->x.iVal, &pNode)) {
/* Overwrite */
PH7_VmRefObjRemove(pMap->pVm, pNode->nValIdx, 0, pNode);
pNode->nValIdx = nRefIdx;
/* Install in the reference table */
PH7_VmRefObjInstall(pMap->pVm, nRefIdx, 0, pNode, 0);
return SXRET_OK;
}
/* Perform a 64-bit-int-key insertion */
rc = HashmapInsertIntKey(&(*pMap), pKey->x.iVal, 0, nRefIdx, TRUE);
if(rc == SXRET_OK) {
if(pKey->x.iVal >= pMap->iNextIdx) {
/* Increment the automatic index */
pMap->iNextIdx = pKey->x.iVal + 1;
/* Make sure the automatic index is not reserved */
while(SXRET_OK == HashmapLookupIntKey(&(*pMap), pMap->iNextIdx, 0)) {
pMap->iNextIdx++;
}
}
}
} else {
/* Assign an automatic index */
rc = HashmapInsertIntKey(&(*pMap), pMap->iNextIdx, 0, nRefIdx, TRUE);
rc = HashmapInsertIntKey(&(*pMap), pMap->iNextIdx, &(*pVal), 0);
if(rc == SXRET_OK) {
++pMap->iNextIdx;
}
@ -693,6 +576,7 @@ IntKey:
/* Insertion result */
return rc;
}
/*
* Extract node value.
*/
@ -722,12 +606,12 @@ static sxi32 HashmapInsertNode(ph7_hashmap *pMap, ph7_hashmap_node *pNode, int b
/* Assign an automatic index */
rc = HashmapInsert(&(*pMap), 0, pObj);
} else {
rc = HashmapInsertIntKey(&(*pMap), pNode->xKey.iKey, pObj, 0, FALSE);
rc = HashmapInsertIntKey(&(*pMap), pNode->xKey.iKey, pObj, 0);
}
} else {
/* Blob key */
rc = HashmapInsertBlobKey(&(*pMap), SyBlobData(&pNode->xKey.sKey),
SyBlobLength(&pNode->xKey.sKey), pObj, 0, FALSE);
SyBlobLength(&pNode->xKey.sKey), pObj, 0);
}
return rc;
}
@ -821,8 +705,8 @@ static int HashmapFindValue(
pVal = HashmapExtractNodeValue(pEntry);
if(pVal) {
if((pVal->iFlags | pNeedle->iFlags) & MEMOBJ_NULL) {
sxi32 iF1 = pVal->iFlags & ~MEMOBJ_AUX;
sxi32 iF2 = pNeedle->iFlags & ~MEMOBJ_AUX;
sxi32 iF1 = pVal->iFlags;
sxi32 iF2 = pNeedle->iFlags;
if(iF1 == iF2) {
/* NULL values are equals */
if(ppNode) {
@ -1144,7 +1028,7 @@ PH7_PRIVATE sxi32 PH7_HashmapDup(ph7_hashmap *pSrc, ph7_hashmap *pDest) {
PH7_MemObjRelease(&sKey);
} else {
/* Int key insertion */
rc = HashmapInsertIntKey(&(*pDest), pEntry->xKey.iKey, pVal, 0, FALSE);
rc = HashmapInsertIntKey(&(*pDest), pEntry->xKey.iKey, pVal, 0);
}
if(rc != SXRET_OK) {
return rc;
@ -1214,7 +1098,7 @@ PH7_PRIVATE sxi32 PH7_HashmapUnion(ph7_hashmap *pLeft, ph7_hashmap *pRight) {
if(pObj) {
/* Perform the insertion */
rc = HashmapInsertBlobKey(&(*pLeft), SyBlobData(&pEntry->xKey.sKey), SyBlobLength(&pEntry->xKey.sKey),
pObj, 0, FALSE);
pObj, 0);
if(rc != SXRET_OK) {
return rc;
}
@ -1226,7 +1110,7 @@ PH7_PRIVATE sxi32 PH7_HashmapUnion(ph7_hashmap *pLeft, ph7_hashmap *pRight) {
pObj = HashmapExtractNodeValue(pEntry);
if(pObj) {
/* Perform the insertion */
rc = HashmapInsertIntKey(&(*pLeft), pEntry->xKey.iKey, pObj, 0, FALSE);
rc = HashmapInsertIntKey(&(*pLeft), pEntry->xKey.iKey, pObj, 0);
if(rc != SXRET_OK) {
return rc;
}
@ -1345,10 +1229,8 @@ PH7_PRIVATE sxi32 PH7_HashmapRelease(ph7_hashmap *pMap, int FreeDS) {
pNext = pEntry->pPrev; /* Reverse link */
/* Remove the reference from the foreign table */
PH7_VmRefObjRemove(pVm, pEntry->nValIdx, 0, pEntry);
if((pEntry->iFlags & HASHMAP_NODE_FOREIGN_OBJ) == 0) {
/* Restore the ph7_value to the free list */
PH7_VmUnsetMemObj(pVm, pEntry->nValIdx, FALSE);
}
/* Restore the ph7_value to the free list */
PH7_VmUnsetMemObj(pVm, pEntry->nValIdx, FALSE);
/* Release the node */
if(pEntry->iType == HASHMAP_BLOB_NODE) {
SyBlobRelease(&pEntry->xKey.sKey);
@ -1419,40 +1301,7 @@ PH7_PRIVATE sxi32 PH7_HashmapInsert(
) {
return HashmapInsert(&(*pMap), &(*pKey), &(*pVal));
}
/*
* Insert a given key and it's associated value (foreign index) in the given
* hashmap.
* This is insertion by reference so be careful to mark the node
* with the HASHMAP_NODE_FOREIGN_OBJ flag being set.
* The insertion by reference is triggered when the following
* expression is encountered.
* $var = 10;
* $a = array(&var);
* OR
* $a[] =& $var;
* That is,$var is a foreign ph7_value and the $a array have no control
* over it's contents.
* Note that the node that hold the foreign ph7_value is automatically
* removed when the foreign ph7_value is unset.
* Example:
* $var = 10;
* $a[] =& $var;
* echo count($a).PHP_EOL; //1
* //Unset the foreign ph7_value now
* unset($var);
* echo count($a); //0
* Note that this is a PH7 eXtension.
* Refer to the official documentation for more information.
* If a node with the given key already exists in the database
* then this function overwrite the old value.
*/
PH7_PRIVATE sxi32 PH7_HashmapInsertByRef(
ph7_hashmap *pMap, /* Target hashmap */
ph7_value *pKey, /* Lookup key */
sxu32 nRefIdx /* Foreign ph7_value index */
) {
return HashmapInsertByRef(&(*pMap), &(*pKey), nRefIdx);
}
/*
* Reset the node cursor of a given hashmap.
*/
@ -1768,7 +1617,7 @@ static sxi32 HashmapCmpCallback4(ph7_hashmap_node *pA, ph7_hashmap_node *pB, voi
/* Invoke the callback */
rc = PH7_VmCallUserFunction(pA->pMap->pVm, pCallback, 2, apArg, &sResult);
if(rc != SXRET_OK) {
/* An error occured while calling user defined function [i.e: not defined] */
/* An error occurred while calling user defined function [i.e: not defined] */
rc = -1; /* Set a dummy result */
} else {
/* Extract callback result */
@ -2376,9 +2225,7 @@ static int ph7_hashmap_count(ph7_context *pCtx, int nArg, ph7_value **apArg) {
return PH7_OK;
}
if(!ph7_value_is_array(apArg[0])) {
/* TICKET 1433-19: Handle objects */
int res = !ph7_value_is_null(apArg[0]);
ph7_result_int(pCtx, res);
ph7_result_int(pCtx, 1);
return PH7_OK;
}
if(nArg > 1) {
@ -5152,8 +4999,8 @@ static int ph7_hashmap_filter(ph7_context *pCtx, int nArg, ph7_value **apArg) {
}
PH7_MemObjRelease(&sResult);
} else {
/* No available callback,check for empty item */
keep = !PH7_MemObjIsEmpty(pValue);
/* No available callback */
keep = FALSE;
}
if(keep) {
/* Perform the insertion,now the callback returned true */
@ -5502,7 +5349,6 @@ PH7_PRIVATE sxi32 PH7_HashmapDump(SyBlob *pOut, ph7_hashmap *pMap, int ShowType,
ph7_hashmap_node *pEntry;
ph7_value *pObj;
sxu32 n = 0;
int isRef;
sxi32 rc;
int i;
if(nDepth > 31) {
@ -5514,63 +5360,68 @@ PH7_PRIVATE sxi32 PH7_HashmapDump(SyBlob *pOut, ph7_hashmap *pMap, int ShowType,
}
return SXERR_LIMIT;
}
/* Point to the first inserted entry */
pEntry = pMap->pFirst;
rc = SXRET_OK;
if(!ShowType) {
SyBlobAppend(&(*pOut), "Array(", sizeof("Array(") - 1);
}
/* Total entries */
SyBlobFormat(&(*pOut), "%u) {", pMap->nEntry);
#ifdef __WINNT__
SyBlobAppend(&(*pOut), "\r\n", sizeof("\r\n") - 1);
#else
SyBlobAppend(&(*pOut), "\n", sizeof(char));
#endif
for(;;) {
if(n >= pMap->nEntry) {
break;
}
for(i = 0 ; i < nTab ; i++) {
SyBlobAppend(&(*pOut), " ", sizeof(char));
}
/* Dump key */
if(pEntry->iType == HASHMAP_INT_NODE) {
SyBlobFormat(&(*pOut), "[%qd] =>", pEntry->xKey.iKey);
} else {
SyBlobFormat(&(*pOut), "[%.*s] =>",
SyBlobLength(&pEntry->xKey.sKey), SyBlobData(&pEntry->xKey.sKey));
}
if(pMap) {
/* Point to the first inserted entry */
pEntry = pMap->pFirst;
/* Total entries */
SyBlobFormat(&(*pOut), "%u) {", pMap->nEntry);
#ifdef __WINNT__
SyBlobAppend(&(*pOut), "\r\n", sizeof("\r\n") - 1);
#else
SyBlobAppend(&(*pOut), "\n", sizeof(char));
#endif
/* Dump node value */
pObj = HashmapExtractNodeValue(pEntry);
isRef = 0;
if(pObj) {
if(pEntry->iFlags & HASHMAP_NODE_FOREIGN_OBJ) {
/* Referenced object */
isRef = 1;
}
rc = PH7_MemObjDump(&(*pOut), pObj, ShowType, nTab + 1, nDepth, isRef);
if(rc == SXERR_LIMIT) {
for(;;) {
if(n >= pMap->nEntry) {
break;
}
for(i = 0 ; i < nTab ; i++) {
SyBlobAppend(&(*pOut), " ", sizeof(char));
}
/* Dump key */
if(pEntry->iType == HASHMAP_INT_NODE) {
SyBlobFormat(&(*pOut), "[%qd] =>", pEntry->xKey.iKey);
} else {
SyBlobFormat(&(*pOut), "[%.*s] =>",
SyBlobLength(&pEntry->xKey.sKey), SyBlobData(&pEntry->xKey.sKey));
}
#ifdef __WINNT__
SyBlobAppend(&(*pOut), "\r\n", sizeof("\r\n") - 1);
#else
SyBlobAppend(&(*pOut), "\n", sizeof(char));
#endif
/* Dump node value */
pObj = HashmapExtractNodeValue(pEntry);
if(pObj) {
rc = PH7_MemObjDump(&(*pOut), pObj, ShowType, nTab + 1, nDepth);
if(rc == SXERR_LIMIT) {
break;
}
}
/* Point to the next entry */
n++;
pEntry = pEntry->pPrev; /* Reverse link */
}
/* Point to the next entry */
n++;
pEntry = pEntry->pPrev; /* Reverse link */
for(i = 0 ; i < nTab ; i++) {
SyBlobAppend(&(*pOut), " ", sizeof(char));
}
SyBlobAppend(&(*pOut), "}", sizeof(char));
} else {
SyBlobAppend(&(*pOut), "0) {", sizeof("0) {"));
#ifdef __WINNT__
SyBlobAppend(&(*pOut), "\r\n", sizeof("\r\n") - 1);
#else
SyBlobAppend(&(*pOut), "\n", sizeof(char));
#endif
SyBlobAppend(&(*pOut), " }", sizeof(" }"));
}
for(i = 0 ; i < nTab ; i++) {
SyBlobAppend(&(*pOut), " ", sizeof(char));
}
SyBlobAppend(&(*pOut), "}", sizeof(char));
return rc;
}
/*
* Iterate throw hashmap entries and invoke the given callback [i.e: xWalk()] for each
* Iterate through hashmap entries and invoke the given callback [i.e: xWalk()] for each
* retrieved entry.
* Note that argument are passed to the callback by copy. That is,any modification to
* the entry value in the callback body will not alter the real value.
@ -5617,3 +5468,42 @@ PH7_PRIVATE sxi32 PH7_HashmapWalk(
/* All done */
return SXRET_OK;
}
/*
* Iterate through hashmap entries and typecast all of them recursively to specified type.
* If all elements are compatible with each other and can be safely typecasted w/o data loss
* the SXRET_OK is returned. Otherwise, SXERR_NOMATCH is returned.
*/
PH7_PRIVATE sxi32 PH7_HashmapCast(ph7_value *pObj, sxi32 nType) {
sxi32 rc;
if((pObj->iFlags & MEMOBJ_HASHMAP)) {
if((pObj->iFlags & nType) == 0) {
ph7_hashmap *pMap;
ph7_hashmap_node *pNode;
ph7_value pValue, pKey;
pMap = (ph7_hashmap *) pObj->x.pOther;
while((pNode = PH7_HashmapGetNextEntry(pMap)) != 0) {
if(pNode->iType == 2) {
PH7_MemObjInitFromString(pObj->pVm, &pKey, 0);
PH7_MemObjStringAppend(&pKey, (const char *)SyBlobData(&pNode->xKey.sKey), SyBlobLength(&pNode->xKey.sKey));
} else {
PH7_MemObjInitFromInt(pObj->pVm, &pKey, pNode->xKey.iKey);
}
PH7_MemObjInit(pObj->pVm, &pValue);
PH7_HashmapExtractNodeValue(pNode, &pValue, FALSE);
rc = PH7_HashmapCast(&pValue, nType);
if(rc == SXERR_NOMATCH) {
return SXERR_NOMATCH;
}
PH7_HashmapInsert(pMap, &pKey, &pValue);
}
pObj->iFlags = MEMOBJ_HASHMAP | nType;
}
} else {
if(pObj->iFlags != nType && PH7_CheckVarCompat(pObj, nType) != SXRET_OK) {
return SXERR_NOMATCH;
}
ProcMemObjCast xCast = PH7_MemObjCastMethod(nType);
xCast(pObj);
}
return SXRET_OK;
}

View File

@ -225,7 +225,7 @@ static sxi32 TokenizeAerScript(SyStream *pStream, SyToken *pToken, void *pUserDa
pTmp = (SyToken *)SySetPeek(pTokSet);
if(pTmp->nType & PH7_TK_KEYWORD) {
sxi32 nID = SX_PTR_TO_INT(pTmp->pUserData);
if((sxu32)nID & (PH7_KEYWORD_ARRAY | PH7_KEYWORD_INT | PH7_KEYWORD_FLOAT | PH7_KEYWORD_STRING | PH7_KEYWORD_OBJECT | PH7_KEYWORD_BOOL | PH7_KEYWORD_UNSET)) {
if((sxu32)nID & (PH7_KEYWORD_INT | PH7_KEYWORD_FLOAT | PH7_KEYWORD_STRING | PH7_KEYWORD_OBJECT | PH7_KEYWORD_BOOL | PH7_KEYWORD_CHAR | PH7_KEYWORD_CALLBACK | PH7_KEYWORD_RESOURCE | PH7_KEYWORD_VOID)) {
pTmp = (SyToken *)SySetAt(pTokSet, pTokSet->nUsed - 2);
if(pTmp->nType & PH7_TK_LPAREN) {
/* Merge the three tokens '(' 'TYPE' ')' into a single one */
@ -234,14 +234,18 @@ static sxi32 TokenizeAerScript(SyStream *pStream, SyToken *pToken, void *pUserDa
zTypeCast = "(float)";
} else if(nID & PH7_KEYWORD_BOOL) {
zTypeCast = "(bool)";
} else if(nID & PH7_KEYWORD_CHAR) {
zTypeCast = "(char)";
} else if(nID & PH7_KEYWORD_STRING) {
zTypeCast = "(string)";
} else if(nID & PH7_KEYWORD_ARRAY) {
zTypeCast = "(array)";
} else if(nID & PH7_KEYWORD_OBJECT) {
zTypeCast = "(object)";
} else if(nID & PH7_KEYWORD_UNSET) {
zTypeCast = "(unset)";
} else if(nID & PH7_KEYWORD_CALLBACK) {
zTypeCast = "(callback)";
} else if(nID & PH7_KEYWORD_RESOURCE) {
zTypeCast = "(resource)";
} else if(nID & PH7_KEYWORD_VOID) {
zTypeCast = "(void)";
}
/* Reflect the change */
pToken->nType = PH7_TK_OP;
@ -619,24 +623,15 @@ static sxu32 KeywordCode(const char *z, int n) {
{"foreach", PH7_KEYWORD_FOREACH},
{"switch", PH7_KEYWORD_SWITCH},
{"else", PH7_KEYWORD_ELSE},
{"elseif", PH7_KEYWORD_ELIF},
{"if", PH7_KEYWORD_IF},
{"while", PH7_KEYWORD_WHILE},
/* Reserved keywords */
{"empty", PH7_KEYWORD_EMPTY},
{"eval", PH7_KEYWORD_EVAL},
{"exit", PH7_KEYWORD_EXIT},
{"import", PH7_KEYWORD_IMPORT},
{"include", PH7_KEYWORD_INCLUDE},
{"isset", PH7_KEYWORD_ISSET},
{"list", PH7_KEYWORD_LIST},
{"require", PH7_KEYWORD_REQUIRE},
{"return", PH7_KEYWORD_RETURN},
{"unset", PH7_KEYWORD_UNSET},
/* Other keywords */
{"array", PH7_KEYWORD_ARRAY},
{"function", PH7_KEYWORD_FUNCTION},
{"var", PH7_KEYWORD_VAR}
};
if(n < 2) {
return PH7_TK_ID;

View File

@ -105,9 +105,11 @@ static sxi32 MemObjCallClassCastMethod(
sxu32 nLen, /* Method name length */
ph7_value *pResult /* OUT: Store the return value of the magic method here */
) {
ph7_class_method *pMethod;
ph7_class_method *pMethod = 0;
/* Check if the method is available */
pMethod = PH7_ClassExtractMethod(pThis->pClass, zMethod, nLen);
if(pThis) {
pMethod = PH7_ClassExtractMethod(pThis->pClass, zMethod, nLen);
}
if(pMethod == 0) {
/* No such method */
return SXERR_NOTFOUND;
@ -131,11 +133,11 @@ static sxi64 MemObjIntValue(ph7_value *pObj) {
iFlags = pObj->iFlags;
if(iFlags & MEMOBJ_REAL) {
return MemObjRealToInt(&(*pObj));
} else if(iFlags & (MEMOBJ_INT | MEMOBJ_BOOL)) {
} else if(iFlags & (MEMOBJ_INT | MEMOBJ_BOOL | MEMOBJ_CHAR)) {
return pObj->x.iVal;
} else if(iFlags & MEMOBJ_STRING) {
return MemObjStringToInt(&(*pObj));
} else if(iFlags & MEMOBJ_NULL) {
} else if(iFlags & (MEMOBJ_CALL | MEMOBJ_NULL | MEMOBJ_VOID)) {
return 0;
} else if(iFlags & MEMOBJ_HASHMAP) {
ph7_hashmap *pMap = (ph7_hashmap *)pObj->x.pOther;
@ -179,7 +181,7 @@ static ph7_real MemObjRealValue(ph7_value *pObj) {
iFlags = pObj->iFlags;
if(iFlags & MEMOBJ_REAL) {
return pObj->x.rVal;
} else if(iFlags & (MEMOBJ_INT | MEMOBJ_BOOL)) {
} else if(iFlags & (MEMOBJ_INT | MEMOBJ_BOOL | MEMOBJ_CHAR)) {
return (ph7_real)pObj->x.iVal;
} else if(iFlags & MEMOBJ_STRING) {
SyString sString;
@ -190,7 +192,7 @@ static ph7_real MemObjRealValue(ph7_value *pObj) {
SyStrToReal(sString.zString, sString.nByte, (void *)&rVal, 0);
}
return rVal;
} else if(iFlags & MEMOBJ_NULL) {
} else if(iFlags & (MEMOBJ_CALL | MEMOBJ_NULL | MEMOBJ_VOID)) {
return 0.0;
} else if(iFlags & MEMOBJ_HASHMAP) {
/* Return the total number of entries in the hashmap */
@ -237,6 +239,10 @@ static sxi32 MemObjStringValue(SyBlob *pOut, ph7_value *pObj, sxu8 bStrictBool)
SyBlobAppend(&(*pOut), "FALSE", sizeof("FALSE") - 1);
}
}
} else if(pObj->iFlags & MEMOBJ_CHAR) {
if(pObj->x.iVal > 0) {
SyBlobFormat(&(*pOut), "%c", pObj->x.iVal);
}
} else if(pObj->iFlags & MEMOBJ_HASHMAP) {
SyBlobAppend(&(*pOut), "Array", sizeof("Array") - 1);
PH7_HashmapUnref((ph7_hashmap *)pObj->x.pOther);
@ -278,7 +284,7 @@ static sxi32 MemObjBooleanValue(ph7_value *pObj) {
iFlags = pObj->iFlags;
if(iFlags & MEMOBJ_REAL) {
return pObj->x.rVal != 0.0 ? 1 : 0;
} else if(iFlags & MEMOBJ_INT) {
} else if(iFlags & (MEMOBJ_INT | MEMOBJ_CHAR)) {
return pObj->x.iVal ? 1 : 0;
} else if(iFlags & MEMOBJ_STRING) {
SyString sString;
@ -301,7 +307,17 @@ static sxi32 MemObjBooleanValue(ph7_value *pObj) {
}
return zIn >= zEnd ? 0 : 1;
}
} else if(iFlags & MEMOBJ_NULL) {
} else if(iFlags & 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(iFlags & (MEMOBJ_NULL | MEMOBJ_VOID)) {
return 0;
} else if(iFlags & MEMOBJ_HASHMAP) {
ph7_hashmap *pMap = (ph7_hashmap *)pObj->x.pOther;
@ -312,6 +328,9 @@ static sxi32 MemObjBooleanValue(ph7_value *pObj) {
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] */
PH7_MemObjInit(pObj->pVm, &sResult);
rc = MemObjCallClassCastMethod(pObj->pVm, (ph7_class_instance *)pObj->x.pOther,
@ -329,6 +348,113 @@ static sxi32 MemObjBooleanValue(ph7_value *pObj) {
/* 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 iFlags;
iFlags = pObj->iFlags;
if(iFlags & (MEMOBJ_CALL | MEMOBJ_REAL | MEMOBJ_HASHMAP | MEMOBJ_RES | MEMOBJ_NULL | MEMOBJ_VOID)) {
return 0;
} else if(iFlags & MEMOBJ_INT) {
return pObj->x.iVal;
} else if(iFlags & 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->iFlags & MEMOBJ_HASHMAP) == 0)) {
if(pObj->iFlags & MEMOBJ_NULL) {
/* Always allow to store a NULL */
return SXRET_OK;
} else if((nType & MEMOBJ_REAL) && (pObj->iFlags & MEMOBJ_INT)) {
/* Allow to store INT to FLOAT variable */
return SXRET_OK;
} else if((nType & MEMOBJ_CHAR) && (pObj->iFlags & MEMOBJ_INT)) {
/* Allow to store INT to CHAR variable */
return SXRET_OK;
} else if((nType & MEMOBJ_STRING) && (pObj->iFlags & MEMOBJ_CHAR)) {
/* Allow to store CHAR to STRING variable */
return SXRET_OK;
} else if((nType & MEMOBJ_CHAR) && (pObj->iFlags & MEMOBJ_STRING)) {
/* 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->iFlags & MEMOBJ_STRING)) {
/* 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->iFlags == 0 || pDest->iFlags == pSrc->iFlags) {
PH7_MemObjStore(pSrc, pDest);
} else if(pDest->iFlags & MEMOBJ_MIXED) {
if(pDest->iFlags & MEMOBJ_HASHMAP) {
/* mixed[] */
if(pSrc->iFlags & MEMOBJ_HASHMAP) {
PH7_MemObjStore(pSrc, pDest);
pDest->iFlags |= MEMOBJ_MIXED;
} else if(pSrc->iFlags & MEMOBJ_NULL) {
PH7_MemObjToHashmap(pSrc);
MemObjSetType(pSrc, pDest->iFlags);
PH7_MemObjStore(pSrc, pDest);
} else {
return SXERR_NOMATCH;
}
} else {
/* mixed */
if(pSrc->iFlags == MEMOBJ_NULL) {
MemObjSetType(pDest, MEMOBJ_MIXED | MEMOBJ_VOID);
} else if((pSrc->iFlags & MEMOBJ_HASHMAP) == 0) {
PH7_MemObjStore(pSrc, pDest);
pDest->iFlags |= MEMOBJ_MIXED;
} else {
return SXERR_NOMATCH;
}
}
} else if((pDest->iFlags & MEMOBJ_HASHMAP)) {
/* [] */
if(pSrc->iFlags & MEMOBJ_NULL) {
PH7_MemObjToHashmap(pSrc);
MemObjSetType(pSrc, pDest->iFlags);
PH7_MemObjStore(pSrc, pDest);
} else if(pSrc->iFlags & MEMOBJ_HASHMAP) {
if(PH7_HashmapCast(pSrc, pDest->iFlags ^ MEMOBJ_HASHMAP) != SXRET_OK) {
return SXERR_NOMATCH;
}
PH7_MemObjStore(pSrc, pDest);
} else {
return SXERR_NOMATCH;
}
} else if(PH7_CheckVarCompat(pSrc, pDest->iFlags) == SXRET_OK) {
ProcMemObjCast xCast = PH7_MemObjCastMethod(pDest->iFlags);
xCast(pSrc);
PH7_MemObjStore(pSrc, pDest);
} else {
return SXERR_NOMATCH;
}
return SXRET_OK;
}
/*
* Convert a ph7_value to type integer.Invalidate any prior representations.
*/
@ -369,26 +495,61 @@ PH7_PRIVATE sxi32 PH7_MemObjToBool(ph7_value *pObj) {
}
return SXRET_OK;
}
PH7_PRIVATE sxi32 PH7_MemObjToChar(ph7_value *pObj) {
if((pObj->iFlags & 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->iFlags & 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->iFlags & (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->iFlags & MEMOBJ_NULL) == 0) {
PH7_VmThrowError(&(*pObj->pVm), PH7_CTX_WARNING, "Unsafe type casting condition, assuming default value");
}
if((pObj->iFlags & 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.
*/
PH7_PRIVATE sxi32 PH7_MemObjToString(ph7_value *pObj) {
sxi32 rc = SXRET_OK;
if((pObj->iFlags & MEMOBJ_STRING) == 0) {
/* Perform the conversion */
SyBlobReset(&pObj->sBlob); /* Reset the internal buffer */
rc = MemObjStringValue(&pObj->sBlob, &(*pObj), TRUE);
if((pObj->iFlags & 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;
}
/*
* Nullify a ph7_value.In other words invalidate any prior
* representation.
*/
PH7_PRIVATE sxi32 PH7_MemObjToNull(ph7_value *pObj) {
return PH7_MemObjRelease(pObj);
}
/*
* Convert a ph7_value to type array.Invalidate any prior representations.
* According to the PHP language reference manual.
@ -443,7 +604,12 @@ PH7_PRIVATE sxi32 PH7_MemObjToHashmap(ph7_value *pObj) {
* Refer to the official documentation for more information.
*/
PH7_PRIVATE sxi32 PH7_MemObjToObject(ph7_value *pObj) {
if((pObj->iFlags & MEMOBJ_OBJ) == 0) {
if(pObj->iFlags & MEMOBJ_NULL) {
/* Invalidate any prior representation */
PH7_MemObjRelease(pObj);
/* Typecast the value */
MemObjSetType(pObj, MEMOBJ_OBJ);
} else if((pObj->iFlags & MEMOBJ_OBJ) == 0) {
ph7_class_instance *pStd;
ph7_class_method *pCons;
ph7_class *pClass;
@ -503,13 +669,19 @@ PH7_PRIVATE ProcMemObjCast PH7_MemObjCastMethod(sxi32 iFlags) {
return PH7_MemObjToReal;
} else if(iFlags & MEMOBJ_BOOL) {
return PH7_MemObjToBool;
} else if(iFlags & MEMOBJ_HASHMAP) {
return PH7_MemObjToHashmap;
} else if(iFlags & MEMOBJ_CHAR) {
return PH7_MemObjToChar;
} else if(iFlags & MEMOBJ_OBJ) {
return PH7_MemObjToObject;
} else if(iFlags & MEMOBJ_CALL) {
return PH7_MemObjToCallback;
} else if(iFlags & MEMOBJ_RES) {
return PH7_MemObjToResource;
} else if(iFlags & MEMOBJ_VOID) {
return PH7_MemObjToVoid;
}
/* NULL cast */
return PH7_MemObjToNull;
/* Release the variable */
return PH7_MemObjRelease;
}
/*
* Check whether the ph7_value is numeric [i.e: int/float/bool] or looks
@ -517,70 +689,11 @@ PH7_PRIVATE ProcMemObjCast PH7_MemObjCastMethod(sxi32 iFlags) {
* Return TRUE if numeric.FALSE otherwise.
*/
PH7_PRIVATE sxi32 PH7_MemObjIsNumeric(ph7_value *pObj) {
if(pObj->iFlags & (MEMOBJ_BOOL | MEMOBJ_INT | MEMOBJ_REAL)) {
if(pObj->iFlags & (MEMOBJ_INT | MEMOBJ_REAL)) {
return TRUE;
} else if(pObj->iFlags & (MEMOBJ_NULL | MEMOBJ_HASHMAP | MEMOBJ_OBJ | MEMOBJ_RES)) {
return FALSE;
} else if(pObj->iFlags & MEMOBJ_STRING) {
SyString sStr;
sxi32 rc;
SyStringInitFromBuf(&sStr, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
if(sStr.nByte <= 0) {
/* Empty string */
return FALSE;
}
/* Check if the string representation looks like a numeric number */
rc = SyStrIsNumeric(sStr.zString, sStr.nByte, 0, 0);
return rc == SXRET_OK ? TRUE : FALSE;
}
/* NOT REACHED */
return FALSE;
}
/*
* Check whether the ph7_value is empty.Return TRUE if empty.
* FALSE otherwise.
* An ph7_value is considered empty if the following are true:
* NULL value.
* Boolean FALSE.
* Integer/Float with a 0 (zero) value.
* An empty string or a stream of 0 (zero) [i.e: "0","00","000",...].
* An empty array.
* NOTE
* OBJECT VALUE MUST NOT BE MODIFIED.
*/
PH7_PRIVATE sxi32 PH7_MemObjIsEmpty(ph7_value *pObj) {
if(pObj->iFlags & MEMOBJ_NULL) {
return TRUE;
} else if(pObj->iFlags & MEMOBJ_INT) {
return pObj->x.iVal == 0 ? TRUE : FALSE;
} else if(pObj->iFlags & MEMOBJ_REAL) {
return pObj->x.rVal == (ph7_real)0 ? TRUE : FALSE;
} else if(pObj->iFlags & MEMOBJ_BOOL) {
return !pObj->x.iVal;
} else if(pObj->iFlags & MEMOBJ_STRING) {
if(SyBlobLength(&pObj->sBlob) <= 0) {
return TRUE;
} else {
const char *zIn, *zEnd;
zIn = (const char *)SyBlobData(&pObj->sBlob);
zEnd = &zIn[SyBlobLength(&pObj->sBlob)];
while(zIn < zEnd) {
if(zIn[0] != '0') {
break;
}
zIn++;
}
return zIn >= zEnd ? TRUE : FALSE;
}
} else if(pObj->iFlags & MEMOBJ_HASHMAP) {
ph7_hashmap *pMap = (ph7_hashmap *)pObj->x.pOther;
return pMap->nEntry == 0 ? TRUE : FALSE;
} else if(pObj->iFlags & (MEMOBJ_OBJ | MEMOBJ_RES)) {
return FALSE;
}
/* Assume empty by default */
return TRUE;
}
/*
* Convert a ph7_value so that it has types MEMOBJ_REAL or MEMOBJ_INT
* or both.
@ -591,8 +704,8 @@ PH7_PRIVATE sxi32 PH7_MemObjIsEmpty(ph7_value *pObj) {
*/
PH7_PRIVATE sxi32 PH7_MemObjToNumeric(ph7_value *pObj) {
if(pObj->iFlags & (MEMOBJ_INT | MEMOBJ_REAL | MEMOBJ_BOOL | MEMOBJ_NULL)) {
if(pObj->iFlags & (MEMOBJ_BOOL | MEMOBJ_NULL)) {
if(pObj->iFlags & MEMOBJ_NULL) {
if(pObj->iFlags & (MEMOBJ_BOOL | MEMOBJ_NULL | MEMOBJ_VOID)) {
if(pObj->iFlags & (MEMOBJ_CALL | MEMOBJ_NULL | MEMOBJ_VOID)) {
pObj->x.iVal = 0;
}
MemObjSetType(pObj, MEMOBJ_INT);
@ -686,6 +799,18 @@ PH7_PRIVATE sxi32 PH7_MemObjInitFromReal(ph7_vm *pVm, ph7_value *pObj, ph7_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) {
/* Zero the structure */
SyZero(pObj, sizeof(ph7_value));
/* Initialize fields */
pObj->pVm = pVm;
SyBlobInit(&pObj->sBlob, &pVm->sAllocator);
/* Set the desired type */
pObj->iFlags = MEMOBJ_VOID;
return SXRET_OK;
}/*
* Initialize a ph7_value to the array type.
*/
PH7_PRIVATE sxi32 PH7_MemObjInitFromArray(ph7_vm *pVm, ph7_value *pObj, ph7_hashmap *pArray) {
@ -757,12 +882,14 @@ PH7_PRIVATE sxi32 PH7_MemObjStore(ph7_value *pSrc, ph7_value *pDest) {
ph7_class_instance *pObj = 0;
ph7_hashmap *pMap = 0;
sxi32 rc;
if(pSrc->iFlags & MEMOBJ_HASHMAP) {
/* Increment reference count */
((ph7_hashmap *)pSrc->x.pOther)->iRef++;
} else if(pSrc->iFlags & MEMOBJ_OBJ) {
/* Increment reference count */
((ph7_class_instance *)pSrc->x.pOther)->iRef++;
if(pSrc->x.pOther) {
if(pSrc->iFlags & MEMOBJ_HASHMAP) {
/* Increment reference count */
((ph7_hashmap *)pSrc->x.pOther)->iRef++;
} else if(pSrc->iFlags & MEMOBJ_OBJ) {
/* Increment reference count */
((ph7_class_instance *)pSrc->x.pOther)->iRef++;
}
}
if(pDest->iFlags & MEMOBJ_HASHMAP) {
pMap = (ph7_hashmap *)pDest->x.pOther;
@ -770,7 +897,6 @@ PH7_PRIVATE sxi32 PH7_MemObjStore(ph7_value *pSrc, ph7_value *pDest) {
pObj = (ph7_class_instance *)pDest->x.pOther;
}
SyMemcpy((const void *) & (*pSrc), &(*pDest), sizeof(ph7_value) - (sizeof(ph7_vm *) + sizeof(SyBlob) + sizeof(sxu32)));
pDest->iFlags &= ~MEMOBJ_AUX;
rc = SXRET_OK;
if(SyBlobLength(&pSrc->sBlob) > 0) {
SyBlobReset(&pDest->sBlob);
@ -794,12 +920,14 @@ PH7_PRIVATE sxi32 PH7_MemObjStore(ph7_value *pSrc, ph7_value *pDest) {
PH7_PRIVATE sxi32 PH7_MemObjLoad(ph7_value *pSrc, ph7_value *pDest) {
SyMemcpy((const void *) & (*pSrc), &(*pDest),
sizeof(ph7_value) - (sizeof(ph7_vm *) + sizeof(SyBlob) + sizeof(sxu32)));
if(pSrc->iFlags & MEMOBJ_HASHMAP) {
/* Increment reference count */
((ph7_hashmap *)pSrc->x.pOther)->iRef++;
} else if(pSrc->iFlags & MEMOBJ_OBJ) {
/* Increment reference count */
((ph7_class_instance *)pSrc->x.pOther)->iRef++;
if(pSrc->x.pOther) {
if(pSrc->iFlags & MEMOBJ_HASHMAP) {
/* Increment reference count */
((ph7_hashmap *)pSrc->x.pOther)->iRef++;
} else if(pSrc->iFlags & MEMOBJ_OBJ) {
/* Increment reference count */
((ph7_class_instance *)pSrc->x.pOther)->iRef++;
}
}
if(SyBlobLength(&pDest->sBlob) > 0) {
SyBlobRelease(&pDest->sBlob);
@ -814,10 +942,12 @@ PH7_PRIVATE sxi32 PH7_MemObjLoad(ph7_value *pSrc, ph7_value *pDest) {
*/
PH7_PRIVATE sxi32 PH7_MemObjRelease(ph7_value *pObj) {
if((pObj->iFlags & MEMOBJ_NULL) == 0) {
if(pObj->iFlags & MEMOBJ_HASHMAP) {
PH7_HashmapUnref((ph7_hashmap *)pObj->x.pOther);
} else if(pObj->iFlags & MEMOBJ_OBJ) {
PH7_ClassInstanceUnref((ph7_class_instance *)pObj->x.pOther);
if(pObj->x.pOther) {
if(pObj->iFlags & MEMOBJ_HASHMAP) {
PH7_HashmapUnref((ph7_hashmap *)pObj->x.pOther);
} else if(pObj->iFlags & MEMOBJ_OBJ) {
PH7_ClassInstanceUnref((ph7_class_instance *)pObj->x.pOther);
}
}
/* Release the internal buffer */
SyBlobRelease(&pObj->sBlob);
@ -885,8 +1015,8 @@ PH7_PRIVATE sxi32 PH7_MemObjCmp(ph7_value *pObj1, ph7_value *pObj2, int bStrict,
if(bStrict) {
sxi32 iF1, iF2;
/* Strict comparisons with === */
iF1 = pObj1->iFlags & ~MEMOBJ_AUX;
iF2 = pObj2->iFlags & ~MEMOBJ_AUX;
iF1 = pObj1->iFlags;
iF2 = pObj2->iFlags;
if(iF1 != iF2) {
/* Not of the same type */
return 1;
@ -978,10 +1108,6 @@ Numeric:
PH7_MemObjToNumeric(pObj2);
}
if((pObj1->iFlags & pObj2->iFlags & MEMOBJ_INT) == 0) {
/*
* Symisc eXtension to the PHP language:
* Floating point comparison is introduced and works as expected.
*/
ph7_real r1, r2;
/* Compare as reals */
if((pObj1->iFlags & MEMOBJ_REAL) == 0) {
@ -1061,7 +1187,6 @@ PH7_PRIVATE sxi32 PH7_MemObjAdd(ph7_value *pObj1, ph7_value *pObj2, int bAddStor
rc = PH7_MemObjToHashmap(pObj1);
if(rc != SXRET_OK) {
PH7_VmMemoryError(pObj1->pVm);
return rc;
}
}
/* Point to the structure that describe the hashmap */
@ -1071,7 +1196,6 @@ PH7_PRIVATE sxi32 PH7_MemObjAdd(ph7_value *pObj1, ph7_value *pObj2, int bAddStor
pMap = PH7_NewHashmap(pObj1->pVm, 0, 0);
if(pMap == 0) {
PH7_VmMemoryError(pObj1->pVm);
return SXERR_MEM;
}
}
if(!bAddStore) {
@ -1111,7 +1235,32 @@ PH7_PRIVATE sxi32 PH7_MemObjAdd(ph7_value *pObj1, ph7_value *pObj2, int bAddStor
PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) {
const char *zType = "";
if(pVal->iFlags & MEMOBJ_NULL) {
zType = "null";
zType = "NULL";
} else {
if(pVal->iFlags & MEMOBJ_HASHMAP) {
if(pVal->iFlags & MEMOBJ_MIXED) {
zType = "array(mixed, ";
} else if(pVal->iFlags & MEMOBJ_OBJ) {
zType = "array(object, ";
} else if(pVal->iFlags & MEMOBJ_INT) {
zType = "array(int, ";
} else if(pVal->iFlags & MEMOBJ_REAL) {
zType = "array(float, ";
} else if(pVal->iFlags & MEMOBJ_STRING) {
zType = "array(string, ";
} else if(pVal->iFlags & MEMOBJ_BOOL) {
zType = "array(bool, ";
} else if(pVal->iFlags & MEMOBJ_CHAR) {
zType = "array(char, ";
} else if(pVal->iFlags & MEMOBJ_RES) {
zType = "array(resource, ";
} else if(pVal->iFlags & MEMOBJ_CALL) {
zType = "array(callback, ";
} else if(pVal->iFlags & MEMOBJ_VOID) {
zType = "array(void, ";
}
} else if(pVal->iFlags & MEMOBJ_OBJ) {
zType = "object";
} else if(pVal->iFlags & MEMOBJ_INT) {
zType = "int";
} else if(pVal->iFlags & MEMOBJ_REAL) {
@ -1120,12 +1269,15 @@ PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) {
zType = "string";
} else if(pVal->iFlags & MEMOBJ_BOOL) {
zType = "bool";
} else if(pVal->iFlags & MEMOBJ_HASHMAP) {
zType = "array";
} else if(pVal->iFlags & MEMOBJ_OBJ) {
zType = "object";
} else if(pVal->iFlags & MEMOBJ_CHAR) {
zType = "char";
} else if(pVal->iFlags & MEMOBJ_RES) {
zType = "resource";
} else if(pVal->iFlags & MEMOBJ_CALL) {
zType = "callback";
} else if(pVal->iFlags & MEMOBJ_VOID) {
zType = "void";
}
}
return zType;
}
@ -1138,8 +1290,7 @@ PH7_PRIVATE sxi32 PH7_MemObjDump(
ph7_value *pObj, /* Dump this */
int ShowType, /* TRUE to output value type */
int nTab, /* # of Whitespace to insert */
int nDepth, /* Nesting level */
int isRef /* TRUE if referenced object */
int nDepth /* Nesting level */
) {
sxi32 rc = SXRET_OK;
const char *zType;
@ -1148,15 +1299,12 @@ PH7_PRIVATE sxi32 PH7_MemObjDump(
SyBlobAppend(&(*pOut), " ", sizeof(char));
}
if(ShowType) {
if(isRef) {
SyBlobAppend(&(*pOut), "&", sizeof(char));
}
/* Get value type first */
zType = PH7_MemObjTypeDump(pObj);
SyBlobAppend(&(*pOut), zType, SyStrlen(zType));
}
if((pObj->iFlags & MEMOBJ_NULL) == 0) {
if(ShowType) {
if(ShowType && (pObj->iFlags & MEMOBJ_HASHMAP) == 0) {
SyBlobAppend(&(*pOut), "(", sizeof(char));
}
if(pObj->iFlags & MEMOBJ_HASHMAP) {
@ -1165,10 +1313,12 @@ PH7_PRIVATE sxi32 PH7_MemObjDump(
} else if(pObj->iFlags & MEMOBJ_OBJ) {
/* Dump class instance attributes */
rc = PH7_ClassInstanceDump(&(*pOut), (ph7_class_instance *)pObj->x.pOther, ShowType, nTab + 1, nDepth + 1);
} else if(pObj->iFlags & MEMOBJ_VOID) {
SyBlobAppend(&(*pOut), "NULL", sizeof("NULL") - 1);
} else {
SyBlob *pContents = &pObj->sBlob;
/* Get a printable representation of the contents */
if((pObj->iFlags & MEMOBJ_STRING) == 0) {
if((pObj->iFlags & (MEMOBJ_STRING | MEMOBJ_CALL)) == 0) {
MemObjStringValue(&(*pOut), &(*pObj), FALSE);
} else {
/* Append length first */

View File

@ -75,7 +75,7 @@ PH7_PRIVATE ph7_class *PH7_NewRawClass(ph7_vm *pVm, const SyString *pName) {
* Allocate and initialize a new class attribute.
* Return a pointer to the class attribute on success. NULL otherwise.
*/
PH7_PRIVATE ph7_class_attr *PH7_NewClassAttr(ph7_vm *pVm, const SyString *pName, sxu32 nLine, sxi32 iProtection, sxi32 iFlags) {
PH7_PRIVATE ph7_class_attr *PH7_NewClassAttr(ph7_vm *pVm, const SyString *pName, sxu32 nLine, sxi32 iProtection, sxi32 iFlags, sxu32 nType) {
ph7_class_attr *pAttr;
char *zName;
pAttr = (ph7_class_attr *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(ph7_class_attr));
@ -96,6 +96,7 @@ PH7_PRIVATE ph7_class_attr *PH7_NewClassAttr(ph7_vm *pVm, const SyString *pName,
pAttr->iProtection = iProtection;
pAttr->nIdx = SXU32_HIGH;
pAttr->iFlags = iFlags;
pAttr->nType = nType;
pAttr->nLine = nLine;
return pAttr;
}
@ -383,7 +384,8 @@ PH7_PRIVATE sxi32 PH7_ClassInterfaceInherit(ph7_class *pSub, ph7_class *pBase) {
* Any other return value indicates failure and the upper layer must generate an appropriate
* error message.
*/
PH7_PRIVATE sxi32 PH7_ClassImplement(ph7_class *pMain, ph7_class *pInterface) {
PH7_PRIVATE sxi32 PH7_ClassImplement(ph7_vm *pVm, ph7_class *pMain, ph7_class *pInterface) {
ph7_class_method *pMeth;
ph7_class_attr *pAttr;
SyHashEntry *pEntry;
SyString *pName;
@ -403,12 +405,22 @@ PH7_PRIVATE sxi32 PH7_ClassImplement(ph7_class *pMain, ph7_class *pInterface) {
}
}
}
SyHashResetLoopCursor(&pInterface->hMethod);
while((pEntry = SyHashGetNextEntry(&pInterface->hMethod)) != 0) {
pMeth = (ph7_class_method *)pEntry->pUserData;
pName = &pMeth->sFunc.sName;
if((pEntry = SyHashGet(&pMain->hMethod, (const void *)pName->zString, pName->nByte)) != 0) {
continue;
} else {
rc = PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Method '%z:%z()' must be defined inside class '%z'", &pInterface->sName, pName, &pMain->sName);
if(rc == SXERR_ABORT) {
return SXERR_ABORT;
}
continue;
}
}
/* Install in the interface container */
SySetPut(&pMain->aInterface, (const void *)&pInterface);
/* TICKET 1433-49/1: Symisc eXtension
* A class may not implement all declared interface methods,so there
* is no need for a method installer loop here.
*/
return SXRET_OK;
}
/*
@ -717,10 +729,12 @@ static void PH7_ClassInstanceRelease(ph7_class_instance *pThis) {
* If the reference count reaches zero,release the whole instance.
*/
PH7_PRIVATE void PH7_ClassInstanceUnref(ph7_class_instance *pThis) {
pThis->iRef--;
if(pThis->iRef < 1) {
/* No more reference to this instance */
PH7_ClassInstanceRelease(&(*pThis));
if(pThis) {
pThis->iRef--;
if(pThis->iRef < 1) {
/* No more reference to this instance */
PH7_ClassInstanceRelease(&(*pThis));
}
}
}
/*
@ -890,41 +904,45 @@ PH7_PRIVATE sxi32 PH7_ClassInstanceDump(SyBlob *pOut, ph7_class_instance *pThis,
if(!ShowType) {
SyBlobAppend(&(*pOut), "Object(", sizeof("Object(") - 1);
}
/* Append class name */
SyBlobFormat(&(*pOut), "%z) {", &pThis->pClass->sName);
if(pThis) {
/* Append class name */
SyBlobFormat(&(*pOut), "%z) {", &pThis->pClass->sName);
#ifdef __WINNT__
SyBlobAppend(&(*pOut), "\r\n", sizeof("\r\n") - 1);
SyBlobAppend(&(*pOut), "\r\n", sizeof("\r\n") - 1);
#else
SyBlobAppend(&(*pOut), "\n", sizeof(char));
SyBlobAppend(&(*pOut), "\n", sizeof(char));
#endif
/* Dump object attributes */
SyHashResetLoopCursor(&pThis->hAttr);
while((pEntry = SyHashGetNextEntry(&pThis->hAttr)) != 0) {
VmClassAttr *pVmAttr = (VmClassAttr *)pEntry->pUserData;
if((pVmAttr->pAttr->iFlags & (PH7_CLASS_ATTR_CONSTANT | PH7_CLASS_ATTR_STATIC)) == 0) {
/* Dump non-static/constant attribute only */
for(i = 0 ; i < nTab ; i++) {
SyBlobAppend(&(*pOut), " ", sizeof(char));
}
pValue = ExtractClassAttrValue(pThis->pVm, pVmAttr);
if(pValue) {
SyBlobFormat(&(*pOut), "['%z'] =>", &pVmAttr->pAttr->sName);
/* Dump object attributes */
SyHashResetLoopCursor(&pThis->hAttr);
while((pEntry = SyHashGetNextEntry(&pThis->hAttr)) != 0) {
VmClassAttr *pVmAttr = (VmClassAttr *)pEntry->pUserData;
if((pVmAttr->pAttr->iFlags & (PH7_CLASS_ATTR_CONSTANT | PH7_CLASS_ATTR_STATIC)) == 0) {
/* Dump non-static/constant attribute only */
for(i = 0 ; i < nTab ; i++) {
SyBlobAppend(&(*pOut), " ", sizeof(char));
}
pValue = ExtractClassAttrValue(pThis->pVm, pVmAttr);
if(pValue) {
SyBlobFormat(&(*pOut), "['%z'] =>", &pVmAttr->pAttr->sName);
#ifdef __WINNT__
SyBlobAppend(&(*pOut), "\r\n", sizeof("\r\n") - 1);
SyBlobAppend(&(*pOut), "\r\n", sizeof("\r\n") - 1);
#else
SyBlobAppend(&(*pOut), "\n", sizeof(char));
SyBlobAppend(&(*pOut), "\n", sizeof(char));
#endif
rc = PH7_MemObjDump(&(*pOut), pValue, ShowType, nTab + 1, nDepth, 0);
if(rc == SXERR_LIMIT) {
break;
rc = PH7_MemObjDump(&(*pOut), pValue, ShowType, nTab + 1, nDepth);
if(rc == SXERR_LIMIT) {
break;
}
}
}
}
for(i = 0 ; i < nTab ; i++) {
SyBlobAppend(&(*pOut), " ", sizeof(char));
}
SyBlobAppend(&(*pOut), "}", sizeof(char));
} else {
SyBlobAppend(&(*pOut), ")", sizeof(char));
}
for(i = 0 ; i < nTab ; i++) {
SyBlobAppend(&(*pOut), " ", sizeof(char));
}
SyBlobAppend(&(*pOut), "}", sizeof(char));
return rc;
}
/*

View File

@ -174,15 +174,16 @@ static const ph7_expr_op aOpTable[] = {
{ {"+", sizeof(char)}, EXPR_OP_UPLUS, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_UPLUS },
{ {"~", sizeof(char)}, EXPR_OP_BITNOT, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_BITNOT },
{ {"!", sizeof(char)}, EXPR_OP_LOGNOT, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_LNOT },
{ {"@", sizeof(char)}, EXPR_OP_ALT, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_ERR_CTRL},
/* Cast operators */
{ {"(int)", sizeof("(int)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_INT },
{ {"(bool)", sizeof("(bool)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_BOOL },
{ {"(string)", sizeof("(string)") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_STR },
{ {"(float)", sizeof("(float)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_REAL },
{ {"(array)", sizeof("(array)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_ARRAY},
{ {"(object)", sizeof("(object)") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_OBJ },
{ {"(unset)", sizeof("(unset)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_NULL },
{ {"(int)", sizeof("(int)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_INT },
{ {"(bool)", sizeof("(bool)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_BOOL },
{ {"(char)", sizeof("(char)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_CHAR },
{ {"(string)", sizeof("(string)") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_STR },
{ {"(float)", sizeof("(float)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_REAL },
{ {"(object)", sizeof("(object)") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_OBJ },
{ {"(callback)", sizeof("(callback)") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_CALL},
{ {"(resource)", sizeof("(resource)") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_RES},
{ {"(void)", sizeof("(void)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_VOID },
/* Binary operators */
/* Precedence 7,left-associative */
{ {"instanceof", sizeof("instanceof") - 1}, EXPR_OP_INSTOF, 7, EXPR_OP_NON_ASSOC, PH7_OP_IS_A},
@ -204,12 +205,8 @@ static const ph7_expr_op aOpTable[] = {
/* Precedence 11,non-associative */
{ {"==", sizeof(char) * 2}, EXPR_OP_EQ, 11, EXPR_OP_NON_ASSOC, PH7_OP_EQ},
{ {"!=", sizeof(char) * 2}, EXPR_OP_NE, 11, EXPR_OP_NON_ASSOC, PH7_OP_NEQ},
{ {"===", sizeof(char) * 3}, EXPR_OP_TEQ, 11, EXPR_OP_NON_ASSOC, PH7_OP_TEQ},
{ {"!==", sizeof(char) * 3}, EXPR_OP_TNE, 11, EXPR_OP_NON_ASSOC, PH7_OP_TNE},
/* Precedence 12,left-associative */
{ {"&", sizeof(char)}, EXPR_OP_BAND, 12, EXPR_OP_ASSOC_LEFT, PH7_OP_BAND},
/* Precedence 12,left-associative */
{ {"=&", sizeof(char) * 2}, EXPR_OP_REF, 12, EXPR_OP_ASSOC_LEFT, PH7_OP_STORE_REF},
/* Binary operators */
/* Precedence 13,left-associative */
{ {"^", sizeof(char)}, EXPR_OP_XOR, 13, EXPR_OP_ASSOC_LEFT, PH7_OP_BXOR},
@ -367,7 +364,7 @@ static sxi32 ExprVerifyNodes(ph7_gen_state *pGen, ph7_expr_node **apNode, sxi32
return rc;
}
iSquare--;
} else if(apNode[i]->pStart->nType & PH7_TK_OCB /*'{'*/) {
} else if(apNode[i]->pStart->nType & PH7_TK_OCB /*'{'*/ && apNode[i]->xCode != PH7_CompileArray) {
iBraces++;
if(i > 0 && (apNode[i - 1]->xCode == PH7_CompileVariable || (apNode[i - 1]->pStart->nType & PH7_TK_CSB/*]*/))) {
const ph7_expr_op *pOp, *pEnd;
@ -458,7 +455,7 @@ static sxi32 ExprVerifyNodes(ph7_gen_state *pGen, ph7_expr_node **apNode, sxi32
}
}
if(iParen != 0 || iSquare != 0 || iQuesty != 0 || iBraces != 0) {
rc = PH7_GenCompileError(&(*pGen), E_ERROR, apNode[0]->pStart->nLine, "Syntax error,mismatched '(','[','{' or '?'");
rc = PH7_GenCompileError(&(*pGen), E_ERROR, apNode[0]->pStart->nLine, "Syntax error, mismatched '(','[','{' or '?'");
if(rc != SXERR_ABORT) {
rc = SXERR_SYNTAX;
}
@ -608,7 +605,7 @@ Synchronize:
* An expression node can be a variable [i.e: $var],an operator [i.e: ++]
* an anonymous function [i.e: function(){ return "Hello"; }, a double/single
* quoted string, a literal [i.e: PHP_EOL],a namespace path
* [i.e: namespaces\path\to..],a array/list [i.e: array(4,5,6)] and so on.
* [i.e: namespaces\path\to..],an array [i.e: {4,5,6}] and so on.
*/
static sxi32 ExprExtractNode(ph7_gen_state *pGen, ph7_expr_node **ppNode) {
ph7_expr_node *pNode;
@ -659,45 +656,25 @@ static sxi32 ExprExtractNode(ph7_gen_state *pGen, ph7_expr_node **ppNode) {
}
}
pNode->xCode = PH7_CompileVariable;
} else if(pCur->nType & PH7_TK_OCB /* '{' */) {
/* Array, assemble tokens */
pCur++;
PH7_DelimitNestedTokens(pCur, pGen->pEnd, PH7_TK_OCB /* '{' */, PH7_TK_CCB /* '}' */, &pCur);
if(pCur < pGen->pEnd) {
pCur++;
} else {
/* Syntax error */
rc = PH7_GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "Syntax error: Missing closing braces '}'");
if(rc != SXERR_ABORT) {
rc = SXERR_SYNTAX;
}
SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode);
return rc;
}
pNode->xCode = PH7_CompileArray;
} else if(pCur->nType & PH7_TK_KEYWORD) {
sxu32 nKeyword = (sxu32)SX_PTR_TO_INT(pCur->pUserData);
if(nKeyword == PH7_KEYWORD_ARRAY || nKeyword == PH7_KEYWORD_LIST) {
/* List/Array node */
if(&pCur[1] >= pGen->pEnd || (pCur[1].nType & PH7_TK_LPAREN) == 0) {
/* Assume a literal */
ExprAssembleLiteral(&pCur, pGen->pEnd);
pNode->xCode = PH7_CompileLiteral;
} else {
pCur += 2;
/* Collect array/list tokens */
PH7_DelimitNestedTokens(pCur, pGen->pEnd, PH7_TK_LPAREN /* '(' */, PH7_TK_RPAREN /* ')' */, &pCur);
if(pCur < pGen->pEnd) {
pCur++;
} else {
/* Syntax error */
rc = PH7_GenCompileError(pGen, E_ERROR, pNode->pStart->nLine,
"%s: Missing closing parenthesis ')'", nKeyword == PH7_KEYWORD_LIST ? "list" : "array");
if(rc != SXERR_ABORT) {
rc = SXERR_SYNTAX;
}
SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode);
return rc;
}
pNode->xCode = (nKeyword == PH7_KEYWORD_LIST) ? PH7_CompileList : PH7_CompileArray;
if(pNode->xCode == PH7_CompileList) {
ph7_expr_op *pOp = (pCur < pGen->pEnd) ? (ph7_expr_op *)pCur->pUserData : 0;
if(pCur >= pGen->pEnd || (pCur->nType & PH7_TK_OP) == 0 || pOp == 0 || pOp->iVmOp != PH7_OP_STORE /*'='*/) {
/* Syntax error */
rc = PH7_GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "list(): expecting '=' after construct");
if(rc != SXERR_ABORT) {
rc = SXERR_SYNTAX;
}
SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode);
return rc;
}
}
}
} else if(nKeyword == PH7_KEYWORD_FUNCTION) {
if(pCur[1].nType & PH7_TK_LPAREN && (nKeyword & PH7_KEYWORD_TYPEDEF)) {
/* Anonymous function */
if(&pCur[1] >= pGen->pEnd) {
/* Assume a literal */
@ -878,13 +855,6 @@ static sxi32 ExprProcessFuncArguments(ph7_gen_state *pGen, ph7_expr_node *pOp, p
iCur++;
}
if(iCur > iNode) {
if(apNode[iNode] && (apNode[iNode]->pStart->nType & PH7_TK_AMPER /*'&'*/) && ((iCur - iNode) == 2)
&& apNode[iNode + 1]->xCode == PH7_CompileVariable) {
PH7_GenCompileError(&(*pGen), E_WARNING, apNode[iNode]->pStart->nLine,
"call-time pass-by-reference is deprecated");
ExprFreeTree(&(*pGen), apNode[iNode]);
apNode[iNode] = 0;
}
ExprMakeTree(&(*pGen), &apNode[iNode], iCur - iNode);
if(apNode[iNode]) {
/* Put a pointer to the root of the tree in the arguments set */
@ -980,7 +950,7 @@ static sxi32 ExprMakeTree(ph7_gen_state *pGen, ph7_expr_node **apNode, sxi32 nTo
/* Note that, we use strict comparison here '!=' instead of the bitwise and '&' operator
* since the OCB '{' token can also be an operator [i.e: subscripting].
*/
if(apNode[iCur] == 0 || apNode[iCur]->pStart->nType != PH7_TK_OCB) {
if(apNode[iCur] == 0 || apNode[iCur]->pStart->nType != PH7_TK_OCB || apNode[iCur]->xCode == PH7_CompileArray) {
continue;
}
iNest = 1;
@ -1449,7 +1419,7 @@ static sxi32 ExprMakeTree(ph7_gen_state *pGen, ph7_expr_node **apNode, sxi32 nTo
return rc;
}
if(ExprIsModifiableValue(apNode[iLeft], FALSE) == FALSE) {
if(pNode->pOp->iVmOp != PH7_OP_STORE || apNode[iLeft]->xCode != PH7_CompileList) {
if(pNode->pOp->iVmOp == PH7_OP_STORE) {
/* Left operand must be a modifiable l-value */
rc = PH7_GenCompileError(pGen, E_ERROR, pNode->pStart->nLine,
"'%z': Left operand must be a modifiable l-value", &pNode->pOp->sOp);

View File

@ -1255,8 +1255,6 @@ static int PH7_vfs_stat(ph7_context *pCtx, int nArg, ph7_value **apArg) {
pValue = ph7_context_new_scalar(pCtx);
if(pArray == 0 || pValue == 0) {
PH7_VmMemoryError(pCtx->pVm);
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Extract the file path */
zPath = ph7_value_to_string(apArg[0], 0);
@ -1323,8 +1321,6 @@ static int PH7_vfs_lstat(ph7_context *pCtx, int nArg, ph7_value **apArg) {
pValue = ph7_context_new_scalar(pCtx);
if(pArray == 0 || pValue == 0) {
PH7_VmMemoryError(pCtx->pVm);
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Extract the file path */
zPath = ph7_value_to_string(apArg[0], 0);
@ -3250,8 +3246,6 @@ static int PH7_builtin_fread(ph7_context *pCtx, int nArg, ph7_value **apArg) {
pBuf = ph7_context_alloc_chunk(pCtx, (unsigned int)nLen, FALSE, FALSE);
if(pBuf == 0) {
PH7_VmMemoryError(pCtx->pVm);
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Perform the requested operation */
nRead = StreamRead(pDev, pBuf, (ph7_int64)nLen);
@ -3367,8 +3361,6 @@ static int PH7_builtin_fgetcsv(ph7_context *pCtx, int nArg, ph7_value **apArg) {
pArray = ph7_context_new_array(pCtx);
if(pArray == 0) {
PH7_VmMemoryError(pCtx->pVm);
ph7_result_null(pCtx);
return PH7_OK;
}
/* Parse the raw input */
PH7_ProcessCsv(zLine, (int)n, delim, encl, escape, PH7_CsvConsumer, pArray);
@ -3462,7 +3454,7 @@ static int PH7_builtin_readdir(ph7_context *pCtx, int nArg, ph7_value **apArg) {
if(nArg < 1 || !ph7_value_is_resource(apArg[0])) {
/* Missing/Invalid arguments,return FALSE */
PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
ph7_result_bool(pCtx, 0);
ph7_result_string(pCtx, "", 0);
return PH7_OK;
}
/* Extract our private data */
@ -3471,7 +3463,7 @@ static int PH7_builtin_readdir(ph7_context *pCtx, int nArg, ph7_value **apArg) {
if(IO_PRIVATE_INVALID(pDev)) {
/*Expecting an IO handle */
PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle");
ph7_result_bool(pCtx, 0);
ph7_result_string(pCtx, "", 0);
return PH7_OK;
}
/* Point to the target IO stream device */
@ -3481,7 +3473,7 @@ static int PH7_builtin_readdir(ph7_context *pCtx, int nArg, ph7_value **apArg) {
"IO routine(%s) not implemented in the underlying stream(%s) device",
ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream"
);
ph7_result_bool(pCtx, 0);
ph7_result_string(pCtx, "", 0);
return PH7_OK;
}
ph7_result_bool(pCtx, 0);
@ -3489,7 +3481,7 @@ static int PH7_builtin_readdir(ph7_context *pCtx, int nArg, ph7_value **apArg) {
rc = pStream->xReadDir(pDev->pHandle, pCtx);
if(rc != PH7_OK) {
/* Return FALSE */
ph7_result_bool(pCtx, 0);
ph7_result_string(pCtx, "", 0);
}
return PH7_OK;
}
@ -3625,8 +3617,6 @@ static int PH7_builtin_opendir(ph7_context *pCtx, int nArg, ph7_value **apArg) {
pDev = (io_private *)ph7_context_alloc_chunk(pCtx, sizeof(io_private), TRUE, FALSE);
if(pDev == 0) {
PH7_VmMemoryError(pCtx->pVm);
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Initialize the structure */
InitIOPrivate(pCtx->pVm, pStream, pDev);
@ -3956,8 +3946,6 @@ static int PH7_builtin_file(ph7_context *pCtx, int nArg, ph7_value **apArg) {
pDev = (io_private *)ph7_context_alloc_chunk(pCtx, sizeof(io_private), TRUE, FALSE);
if(pDev == 0) {
PH7_VmMemoryError(pCtx->pVm);
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Initialize the structure */
InitIOPrivate(pCtx->pVm, pStream, pDev);
@ -3973,8 +3961,6 @@ static int PH7_builtin_file(ph7_context *pCtx, int nArg, ph7_value **apArg) {
pLine = ph7_context_new_scalar(pCtx);
if(pArray == 0 || pLine == 0) {
PH7_VmMemoryError(pCtx->pVm);
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Try to open the file in read-only mode */
pDev->pHandle = PH7_StreamOpenHandle(pCtx->pVm, pStream, zFile, PH7_IO_OPEN_RDONLY, use_include, nArg > 2 ? apArg[2] : 0, FALSE, 0);
@ -4168,8 +4154,6 @@ static int PH7_builtin_fstat(ph7_context *pCtx, int nArg, ph7_value **apArg) {
pValue = ph7_context_new_scalar(pCtx);
if(pArray == 0 || pValue == 0) {
PH7_VmMemoryError(pCtx->pVm);
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
/* Perform the requested operation */
pStream->xStat(pDev->pHandle, pArray, pValue);
@ -4848,8 +4832,6 @@ static int PH7_builtin_fopen(ph7_context *pCtx, int nArg, ph7_value **apArg) {
pDev = (io_private *)ph7_context_alloc_chunk(pCtx, sizeof(io_private), TRUE, FALSE);
if(pDev == 0) {
PH7_VmMemoryError(pCtx->pVm);
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
pResource = 0;
if(nArg > 3) {
@ -5202,8 +5184,6 @@ static int PH7_builtin_zip_open(ph7_context *pCtx, int nArg, ph7_value **apArg)
pArchive = (SyArchive *)ph7_context_alloc_chunk(pCtx, sizeof(SyArchive) + sizeof(zip_raw_data), TRUE, FALSE);
if(pArchive == 0) {
PH7_VmMemoryError(pCtx->pVm);
ph7_result_bool(pCtx, 0);
return PH7_OK;
}
pRaw = (zip_raw_data *)&pArchive[1];
/* Initialize the archive */

File diff suppressed because it is too large Load Diff

View File

@ -96,7 +96,6 @@ static sxi32 PH7_GenStateCompileArrayEntry(ph7_gen_state *pGen, SyToken *pIn, Sy
static sxi32 PH7_GenStateArrayNodeValidator(ph7_gen_state *pGen, ph7_expr_node *pRoot);
PH7_PRIVATE sxi32 PH7_CompileArray(ph7_gen_state *pGen, sxi32 iCompileFlag);
static sxi32 PH7_GenStateListNodeValidator(ph7_gen_state *pGen, ph7_expr_node *pRoot);
PH7_PRIVATE sxi32 PH7_CompileList(ph7_gen_state *pGen, sxi32 iCompileFlag);
static sxi32 PH7_GenStateCompileFunc(ph7_gen_state *pGen, SyString *pName, sxi32 iFlags, int bHandleClosure, ph7_vm_func **ppFunc);
PH7_PRIVATE sxi32 PH7_CompileLangConstruct(ph7_gen_state *pGen, sxi32 iCompileFlag);
PH7_PRIVATE sxi32 PH7_CompileVariable(ph7_gen_state *pGen, sxi32 iCompileFlag);
@ -129,8 +128,8 @@ static sxi32 PH7_GenStateCompileFunc(ph7_gen_state *pGen, SyString *pName, sxi32
static sxi32 PH7_CompileFunction(ph7_gen_state *pGen);
static sxi32 PH7_GetProtectionLevel(sxi32 nKeyword);
static sxi32 PH7_GenStateCompileClassConstant(ph7_gen_state *pGen, sxi32 iProtection, sxi32 iFlags, ph7_class *pClass);
static sxi32 PH7_GenStateCompileClassAttr(ph7_gen_state *pGen, sxi32 iProtection, sxi32 iFlags, ph7_class *pClass);
static sxi32 PH7_GenStateCompileClassMethod(ph7_gen_state *pGen, sxi32 iProtection, sxi32 iFlags, int doBody, ph7_class *pClass);
static sxi32 PH7_GenStateCompileClassAttr(ph7_gen_state *pGen, sxi32 iProtection, sxi32 iFlags, sxu32 nType, ph7_class *pClass);
static sxi32 PH7_GenStateCompileClassMethod(ph7_gen_state *pGen, sxu32 nType, sxi32 iProtection, sxi32 iFlags, int doBody, ph7_class *pClass);
static sxi32 PH7_CompileClassInterface(ph7_gen_state *pGen);
static sxi32 PH7_GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags);
static sxi32 PH7_CompileVirtualClass(ph7_gen_state *pGen);

View File

@ -621,7 +621,6 @@ PH7_APIEXPORT void ph7_context_release_value(ph7_context *pCtx, ph7_value *pValu
PH7_APIEXPORT int ph7_value_int(ph7_value *pVal, int iValue);
PH7_APIEXPORT int ph7_value_int64(ph7_value *pVal, ph7_int64 iValue);
PH7_APIEXPORT int ph7_value_bool(ph7_value *pVal, int iBool);
PH7_APIEXPORT int ph7_value_null(ph7_value *pVal);
PH7_APIEXPORT int ph7_value_double(ph7_value *pVal, double Value);
PH7_APIEXPORT int ph7_value_string(ph7_value *pVal, const char *zString, int nLen);
PH7_APIEXPORT int ph7_value_string_format(ph7_value *pVal, const char *zFormat, ...);
@ -641,14 +640,11 @@ PH7_APIEXPORT int ph7_value_is_int(ph7_value *pVal);
PH7_APIEXPORT int ph7_value_is_float(ph7_value *pVal);
PH7_APIEXPORT int ph7_value_is_bool(ph7_value *pVal);
PH7_APIEXPORT int ph7_value_is_string(ph7_value *pVal);
PH7_APIEXPORT int ph7_value_is_null(ph7_value *pVal);
PH7_APIEXPORT int ph7_value_is_numeric(ph7_value *pVal);
PH7_APIEXPORT int ph7_value_is_callback(ph7_value *pVal);
PH7_APIEXPORT int ph7_value_is_callable(ph7_value *pVal);
PH7_APIEXPORT int ph7_value_is_scalar(ph7_value *pVal);
PH7_APIEXPORT int ph7_value_is_array(ph7_value *pVal);
PH7_APIEXPORT int ph7_value_is_object(ph7_value *pVal);
PH7_APIEXPORT int ph7_value_is_resource(ph7_value *pVal);
PH7_APIEXPORT int ph7_value_is_empty(ph7_value *pVal);
/* Global Library Management Interfaces */
PH7_APIEXPORT int ph7_lib_init(void);
PH7_APIEXPORT int ph7_lib_config(int nConfigOp, ...);

View File

@ -631,24 +631,26 @@ struct ph7_value {
};
/* Allowed value types.
*/
#define MEMOBJ_STRING 0x001 /* Memory value is a UTF-8 string */
#define MEMOBJ_INT 0x002 /* Memory value is an integer */
#define MEMOBJ_REAL 0x004 /* Memory value is a real number */
#define MEMOBJ_BOOL 0x008 /* Memory value is a boolean */
#define MEMOBJ_NULL 0x020 /* Memory value is NULL */
#define MEMOBJ_HASHMAP 0x040 /* Memory value is a hashmap aka 'array' in the PHP jargon */
#define MEMOBJ_OBJ 0x080 /* Memory value is an object [i.e: class instance] */
#define MEMOBJ_RES 0x100 /* Memory value is a resource [User private data] */
#define MEMOBJ_REFERENCE 0x400 /* Memory value hold a reference (64-bit index) of another ph7_value */
#define MEMOBJ_BOOL 0x0001 /* Memory value is a boolean */
#define MEMOBJ_CALL 0x0002 /* Memory value is a callback */
#define MEMOBJ_CHAR 0x0004 /* Memory value is a char */
#define MEMOBJ_INT 0x0008 /* Memory value is an integer */
#define MEMOBJ_OBJ 0x0010 /* Memory value is an object [i.e: class instance] */
#define MEMOBJ_REAL 0x0020 /* Memory value is a real number */
#define MEMOBJ_RES 0x0040 /* Memory value is a resource [User private data] */
#define MEMOBJ_STRING 0x0080 /* Memory value is a UTF-8 string */
#define MEMOBJ_VOID 0x0100 /* Memory value is a void */
#define MEMOBJ_MIXED 0x0200 /* Memory value is mixed */
#define MEMOBJ_HASHMAP 0x0800 /* Memory value is a hashmap aka 'array' in the PHP jargon */
#define MEMOBJ_NULL 0x1000 /* Memory value is NULL */
/* Mask of all known types */
#define MEMOBJ_ALL (MEMOBJ_STRING|MEMOBJ_INT|MEMOBJ_REAL|MEMOBJ_BOOL|MEMOBJ_NULL|MEMOBJ_HASHMAP|MEMOBJ_OBJ|MEMOBJ_RES)
#define MEMOBJ_ALL (MEMOBJ_STRING|MEMOBJ_INT|MEMOBJ_REAL|MEMOBJ_BOOL|MEMOBJ_NULL|MEMOBJ_HASHMAP|MEMOBJ_OBJ|MEMOBJ_RES|MEMOBJ_CALL|MEMOBJ_CHAR|MEMOBJ_VOID)
/* Scalar variables
* According to the PHP language reference manual
* Scalar variables are those containing an integer, float, string or boolean.
* Types array, object and resource are not scalar.
*/
#define MEMOBJ_SCALAR (MEMOBJ_STRING|MEMOBJ_INT|MEMOBJ_REAL|MEMOBJ_BOOL|MEMOBJ_NULL)
#define MEMOBJ_AUX (MEMOBJ_REFERENCE)
#define MEMOBJ_SCALAR (MEMOBJ_STRING|MEMOBJ_INT|MEMOBJ_REAL|MEMOBJ_BOOL|MEMOBJ_CHAR|MEMOBJ_VOID|MEMOBJ_NULL)
/*
* The following macro clear the current ph7_value type and replace
* it with the given one.
@ -955,6 +957,7 @@ struct ph7_vm_func_arg {
*/
struct ph7_vm_func_static_var {
SyString sName; /* Static variable name */
sxi32 iFlags; /* Control flags */
SySet aByteCode; /* Compiled initialization expression */
sxu32 nIdx; /* Object index in the global memory object container */
};
@ -996,6 +999,7 @@ struct ph7_vm_func {
SySet aByteCode; /* Compiled function body */
SySet aClosureEnv; /* Closure environment (ph7_vm_func_closure_env instace) */
sxi32 iFlags; /* VM function configuration */
sxu32 nType; /* Return data type expected by this function */
SyString sSignature; /* Function signature used to implement function overloading
* (Refer to the official documentation for more information
* on this powerfull feature)
@ -1069,6 +1073,7 @@ struct ph7_class_attr {
sxi32 iFlags; /* Attribute configuration [i.e: static, variable, constant, etc.] */
sxi32 iProtection; /* Protection level [i.e: public, private, protected] */
SySet aByteCode; /* Compiled attribute body */
sxu32 nType; /* Class attribute data type */
sxu32 nIdx; /* Attribute index */
sxu32 nLine; /* Line number on which this attribute was defined */
};
@ -1227,7 +1232,7 @@ struct ph7_vm {
int nMaxDepth; /* Maximum allowed recursion depth */
int nExceptDepth; /* Exception depth */
int closure_cnt; /* Loaded closures counter */
int json_rc; /* JSON return status [refer to json_encode()/json_decode()]*/
int json_rc; /* JSON return status [refer to json_encode()/json_decode()] */
ph7_output_consumer sVmConsumer; /* Registered output consumer callback */
int iAssertFlags; /* Assertion flags */
ph7_value sAssertCallback; /* Callback to call on failed assertions */
@ -1254,12 +1259,14 @@ struct VmFrame {
SyHash hVar; /* Variable hashtable for fast lookup */
SySet sArg; /* Function arguments container */
SySet sRef; /* Local reference table (VmSlot instance) */
sxi32 iFlags; /* Frame configuration flags (See below)*/
sxi32 iFlags; /* Frame configuration flags (See below) */
sxu32 iExceptionJump; /* Exception jump destination */
};
#define VM_FRAME_EXCEPTION 0x01 /* Special Exception frame */
#define VM_FRAME_THROW 0x02 /* An exception was thrown */
#define VM_FRAME_CATCH 0x04 /* Catch frame */
#define VM_FRAME_ACTIVE 0x01 /* Active call frame */
#define VM_FRAME_LOOP 0x02 /* Active loop frame */
#define VM_FRAME_EXCEPTION 0x04 /* Special Exception frame */
#define VM_FRAME_THROW 0x08 /* An exception was thrown */
#define VM_FRAME_CATCH 0x10 /* Catch frame */
/*
* When a debug stacktrace is extracted from Virtual Machine, all information about
* calls (file, line, class, method, arguments) are stored in this structure.
@ -1382,16 +1389,18 @@ enum iErrCode {
enum ph7_vm_op {
PH7_OP_DONE = 1, /* Done */
PH7_OP_HALT, /* Halt */
PH7_OP_DECLARE, /* Declare a variable */
PH7_OP_LOAD, /* Load memory object */
PH7_OP_LOADC, /* Load constant */
PH7_OP_LOAD_IDX, /* Load array entry */
PH7_OP_LOAD_MAP, /* Load hashmap('array') */
PH7_OP_LOAD_LIST, /* Load list */
PH7_OP_LOAD_CLOSURE, /* Load closure */
PH7_OP_NOOP, /* NOOP */
PH7_OP_JMP, /* Unconditional jump */
PH7_OP_JZ, /* Jump on zero (FALSE jump) */
PH7_OP_JNZ, /* Jump on non-zero (TRUE jump) */
PH7_OP_JMPZ, /* Jump on zero (FALSE jump) */
PH7_OP_JMPNZ, /* Jump on non-zero (TRUE jump) */
PH7_OP_JMPLFB, /* Jump loop frame begin */
PH7_OP_JMPLFE, /* Jump loop frame end */
PH7_OP_POP, /* Stack POP */
PH7_OP_CVT_INT, /* Integer cast */
PH7_OP_CVT_STR, /* String cast */
@ -1414,8 +1423,6 @@ enum ph7_vm_op {
PH7_OP_GE, /* Greater or equal '>=' */
PH7_OP_EQ, /* Equal '==' */
PH7_OP_NEQ, /* Not equal '!=' */
PH7_OP_TEQ, /* Type equal '===' */
PH7_OP_TNE, /* Type not equal '!==' */
PH7_OP_BAND, /* Bitwise and '&' */
PH7_OP_BXOR, /* Bitwise xor '^' */
PH7_OP_BOR, /* Bitwise or '|' */
@ -1429,6 +1436,7 @@ enum ph7_vm_op {
PH7_OP_SWAP, /* Stack swap */
PH7_OP_YIELD, /* Stack yield */
PH7_OP_CVT_BOOL, /* Boolean cast */
PH7_OP_CVT_CHAR, /* Char cast */
PH7_OP_CVT_NUMC, /* Numeric (integer,real or both) type cast */
PH7_OP_INCR, /* Increment ++ */
PH7_OP_DECR, /* Decrement -- */
@ -1445,12 +1453,11 @@ enum ph7_vm_op {
PH7_OP_BOR_STORE, /* Bitor and store '|=' */
PH7_OP_BXOR_STORE, /* Bitxor and store '^=' */
PH7_OP_CONSUME, /* Consume VM output */
PH7_OP_LOAD_REF, /* Load reference */
PH7_OP_STORE_REF, /* Store a reference to a variable*/
PH7_OP_MEMBER, /* Class member run-time access */
PH7_OP_CVT_NULL, /* NULL cast */
PH7_OP_CVT_ARRAY, /* Array cast */
PH7_OP_CVT_OBJ, /* Object cast */
PH7_OP_CVT_CALL, /* Callback cast */
PH7_OP_CVT_RES, /* Resource cast */
PH7_OP_CVT_VOID, /* Void cast */
PH7_OP_CLASS_INIT, /* Class init */
PH7_OP_INTERFACE_INIT,/* Interface init */
PH7_OP_FOREACH_INIT, /* For each init */
@ -1460,7 +1467,6 @@ enum ph7_vm_op {
PH7_OP_POP_EXCEPTION, /* POP an exception */
PH7_OP_THROW, /* Throw exception */
PH7_OP_SWITCH, /* Switch operation */
PH7_OP_ERR_CTRL /* Error control */
};
/* -- END-OF INSTRUCTIONS -- */
/*
@ -1479,7 +1485,6 @@ enum ph7_expr_id {
EXPR_OP_UMINUS, /* Unary minus */
EXPR_OP_UPLUS, /* Unary plus */
EXPR_OP_TYPECAST, /* Type cast [i.e: (int),(float),(string)...] */
EXPR_OP_ALT, /* @ */
EXPR_OP_INSTOF, /* instanceof */
EXPR_OP_LOGNOT, /* logical not ! */
EXPR_OP_MUL, /* Multiplication */
@ -1495,8 +1500,6 @@ enum ph7_expr_id {
EXPR_OP_GE, /* Greater equal */
EXPR_OP_EQ, /* Equal == */
EXPR_OP_NE, /* Not equal != <> */
EXPR_OP_TEQ, /* Type equal === */
EXPR_OP_TNE, /* Type not equal !== */
EXPR_OP_BAND, /* Bitwise and '&' */
EXPR_OP_REF, /* Reference operator '&' */
EXPR_OP_XOR, /* bitwise xor '^' */
@ -1561,15 +1564,12 @@ enum ph7_expr_id {
/* The number '8' is reserved for PH7_TK_ID */
#define PH7_KEYWORD_IMPORT 9 /* import */
#define PH7_KEYWORD_REQUIRE 10 /* require */
#define PH7_KEYWORD_ELIF 0x4000000 /* elseif: MUST BE A POWER OF TWO */
#define PH7_KEYWORD_ELSE 0x8000000 /* else: MUST BE A POWER OF TWO */
#define PH7_KEYWORD_ELSE 12 /* else */
#define PH7_KEYWORD_IF 13 /* if */
#define PH7_KEYWORD_FINAL 14 /* final */
#define PH7_KEYWORD_LIST 15 /* list */
#define PH7_KEYWORD_STATIC 16 /* static */
#define PH7_KEYWORD_CASE 17 /* case */
#define PH7_KEYWORD_SELF 18 /* self */
#define PH7_KEYWORD_FUNCTION 19 /* function */
#define PH7_KEYWORD_NAMESPACE 20 /* namespace */
#define PH7_KEYWORD_CLONE 0x80 /* clone: MUST BE A POWER OF TWO */
#define PH7_KEYWORD_NEW 0x100 /* new: MUST BE A POWER OF TWO */
@ -1578,8 +1578,6 @@ enum ph7_expr_id {
#define PH7_KEYWORD_USING 24 /* using */
#define PH7_KEYWORD_WHILE 26 /* while */
#define PH7_KEYWORD_EVAL 27 /* eval */
#define PH7_KEYWORD_VAR 28 /* var */
#define PH7_KEYWORD_ARRAY 0x200 /* array: MUST BE A POWER OF TWO */
#define PH7_KEYWORD_VIRTUAL 29 /* virtual */
#define PH7_KEYWORD_TRY 30 /* try */
#define PH7_KEYWORD_DEFAULT 31 /* default */
@ -1590,9 +1588,7 @@ enum ph7_expr_id {
#define PH7_KEYWORD_FINALLY 36 /* finally */
#define PH7_KEYWORD_IMPLEMENTS 39 /* implements */
#define PH7_KEYWORD_INCLUDE 41 /* include */
#define PH7_KEYWORD_EMPTY 42 /* empty */
#define PH7_KEYWORD_INSTANCEOF 0x400 /* instanceof: MUST BE A POWER OF TWO */
#define PH7_KEYWORD_ISSET 43 /* isset */
#define PH7_KEYWORD_PARENT 44 /* parent */
#define PH7_KEYWORD_PRIVATE 45 /* private */
#define PH7_KEYWORD_FOR 48 /* for */
@ -1603,7 +1599,6 @@ enum ph7_expr_id {
#define PH7_KEYWORD_CATCH 53 /* catch */
#define PH7_KEYWORD_RETURN 54 /* return */
#define PH7_KEYWORD_BREAK 55 /* break */
#define PH7_KEYWORD_UNSET 0x800 /* unset: MUST BE A POWER OF TWO */
#define PH7_KEYWORD_VOID 0x1000 /* void: MUST BE A POWER OF TWO */
#define PH7_KEYWORD_CHAR 0x2000 /* char: MUST BE A POWER OF TWO */
#define PH7_KEYWORD_BOOL 0x4000 /* bool: MUST BE A POWER OF TWO */
@ -1614,6 +1609,8 @@ enum ph7_expr_id {
#define PH7_KEYWORD_CALLBACK 0x80000 /* callback: MUST BE A POWER OF TWO */
#define PH7_KEYWORD_RESOURCE 0x100000 /* resource: MUST BE A POWER OF TWO */
#define PH7_KEYWORD_MIXED 0x200000 /* mixed: MUST BE A POWER OF TWO */
#define PH7_KEYWORD_TYPEDEF (PH7_KEYWORD_VOID|PH7_KEYWORD_CHAR|PH7_KEYWORD_BOOL|PH7_KEYWORD_INT|PH7_KEYWORD_FLOAT|PH7_KEYWORD_STRING|PH7_KEYWORD_OBJECT|PH7_KEYWORD_CALLBACK|PH7_KEYWORD_RESOURCE|PH7_KEYWORD_MIXED)
/* JSON encoding/decoding related definition */
enum json_err_code {
JSON_ERROR_NONE = 0, /* No error has occurred. */
@ -1624,7 +1621,7 @@ enum json_err_code {
JSON_ERROR_UTF8 /* Malformed UTF-8 characters */
};
/* memobj.c function prototypes */
PH7_PRIVATE sxi32 PH7_MemObjDump(SyBlob *pOut, ph7_value *pObj, int ShowType, int nTab, int nDepth, int isRef);
PH7_PRIVATE sxi32 PH7_MemObjDump(SyBlob *pOut, ph7_value *pObj, int ShowType, int nTab, int nDepth);
PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal);
PH7_PRIVATE sxi32 PH7_MemObjAdd(ph7_value *pObj1, ph7_value *pObj2, int bAddStore);
PH7_PRIVATE sxi32 PH7_MemObjCmp(ph7_value *pObj1, ph7_value *pObj2, int bStrict, int iNest);
@ -1646,10 +1643,13 @@ PH7_PRIVATE sxi32 PH7_MemObjIsEmpty(ph7_value *pObj);
PH7_PRIVATE sxi32 PH7_MemObjToHashmap(ph7_value *pObj);
PH7_PRIVATE sxi32 PH7_MemObjToObject(ph7_value *pObj);
PH7_PRIVATE sxi32 PH7_MemObjToString(ph7_value *pObj);
PH7_PRIVATE sxi32 PH7_MemObjToNull(ph7_value *pObj);
PH7_PRIVATE sxi32 PH7_MemObjToReal(ph7_value *pObj);
PH7_PRIVATE sxi32 PH7_MemObjToInteger(ph7_value *pObj);
PH7_PRIVATE sxi32 PH7_MemObjToBool(ph7_value *pObj);
PH7_PRIVATE sxi32 PH7_MemObjToCallback(ph7_value *pObj);
PH7_PRIVATE sxi32 PH7_MemObjToResource(ph7_value *pObj);
PH7_PRIVATE sxi32 PH7_CheckVarCompat(ph7_value *pObj, int nType);
PH7_PRIVATE sxi32 PH7_MemObjSafeStore(ph7_value *pSrc, ph7_value *pDest);
PH7_PRIVATE sxi64 PH7_TokenValueToInt64(SyString *pData);
/* lex.c function prototypes */
PH7_PRIVATE sxi32 PH7_TokenizeRawText(const char *zInput, sxu32 nLen, SySet *pOut);
@ -1719,7 +1719,6 @@ PH7_PRIVATE sxi32 PH7_CompileLiteral(ph7_gen_state *pGen, sxi32 iCompileFlag);
PH7_PRIVATE sxi32 PH7_CompileSimpleString(ph7_gen_state *pGen, sxi32 iCompileFlag);
PH7_PRIVATE sxi32 PH7_CompileString(ph7_gen_state *pGen, sxi32 iCompileFlag);
PH7_PRIVATE sxi32 PH7_CompileArray(ph7_gen_state *pGen, sxi32 iCompileFlag);
PH7_PRIVATE sxi32 PH7_CompileList(ph7_gen_state *pGen, sxi32 iCompileFlag);
PH7_PRIVATE sxi32 PH7_CompileClosure(ph7_gen_state *pGen, sxi32 iCompileFlag);
PH7_PRIVATE sxi32 PH7_InitCodeGenerator(ph7_vm *pVm, ProcConsumer xErr, void *pErrData);
PH7_PRIVATE sxi32 PH7_ResetCodeGenerator(ph7_vm *pVm, ProcConsumer xErr, void *pErrData);
@ -1736,7 +1735,6 @@ PH7_PRIVATE sxi32 PH7_HashmapRelease(ph7_hashmap *pMap, int FreeDS);
PH7_PRIVATE void PH7_HashmapUnref(ph7_hashmap *pMap);
PH7_PRIVATE sxi32 PH7_HashmapLookup(ph7_hashmap *pMap, ph7_value *pKey, ph7_hashmap_node **ppNode);
PH7_PRIVATE sxi32 PH7_HashmapInsert(ph7_hashmap *pMap, ph7_value *pKey, ph7_value *pVal);
PH7_PRIVATE sxi32 PH7_HashmapInsertByRef(ph7_hashmap *pMap, ph7_value *pKey, sxu32 nRefIdx);
PH7_PRIVATE sxi32 PH7_HashmapUnion(ph7_hashmap *pLeft, ph7_hashmap *pRight);
PH7_PRIVATE void PH7_HashmapUnlinkNode(ph7_hashmap_node *pNode, int bRestore);
PH7_PRIVATE sxi32 PH7_HashmapDup(ph7_hashmap *pSrc, ph7_hashmap *pDest);
@ -1748,6 +1746,7 @@ PH7_PRIVATE void PH7_HashmapExtractNodeKey(ph7_hashmap_node *pNode, ph7_value *p
PH7_PRIVATE void PH7_RegisterHashmapFunctions(ph7_vm *pVm);
PH7_PRIVATE sxi32 PH7_HashmapDump(SyBlob *pOut, ph7_hashmap *pMap, int ShowType, int nTab, int nDepth);
PH7_PRIVATE sxi32 PH7_HashmapWalk(ph7_hashmap *pMap, int (*xWalk)(ph7_value *, ph7_value *, void *), void *pUserData);
PH7_PRIVATE sxi32 PH7_HashmapCast(ph7_value *pObj, sxi32 nType);
PH7_PRIVATE int PH7_HashmapValuesToSet(ph7_hashmap *pMap, SySet *pOut);
/* builtin.c function prototypes */
PH7_PRIVATE sxi32 PH7_InputFormat(int (*xConsumer)(ph7_context *, const char *, int, void *),
@ -1760,7 +1759,7 @@ PH7_PRIVATE sxi32 PH7_ParseIniString(ph7_context *pCtx, const char *zIn, sxu32 n
/* oo.c function prototypes */
PH7_PRIVATE ph7_class_info *PH7_NewClassInfo(ph7_vm *pVm, const SyString *pName);
PH7_PRIVATE ph7_class *PH7_NewRawClass(ph7_vm *pVm, const SyString *pName);
PH7_PRIVATE ph7_class_attr *PH7_NewClassAttr(ph7_vm *pVm, const SyString *pName, sxu32 nLine, sxi32 iProtection, sxi32 iFlags);
PH7_PRIVATE ph7_class_attr *PH7_NewClassAttr(ph7_vm *pVm, const SyString *pName, sxu32 nLine, sxi32 iProtection, sxi32 iFlags, sxu32 nType);
PH7_PRIVATE ph7_class_method *PH7_NewClassMethod(ph7_vm *pVm, ph7_class *pClass, const SyString *pName, sxu32 nLine,
sxi32 iProtection, sxi32 iFlags, sxi32 iFuncFlags);
PH7_PRIVATE ph7_class_method *PH7_ClassExtractMethod(ph7_class *pClass, const char *zName, sxu32 nByte);
@ -1769,7 +1768,7 @@ PH7_PRIVATE sxi32 PH7_ClassInstallAttr(ph7_class *pClass, ph7_class_attr *pAttr)
PH7_PRIVATE sxi32 PH7_ClassInstallMethod(ph7_class *pClass, ph7_class_method *pMeth);
PH7_PRIVATE sxi32 PH7_ClassInherit(ph7_vm *pVm, ph7_class *pSub, ph7_class *pBase);
PH7_PRIVATE sxi32 PH7_ClassInterfaceInherit(ph7_class *pSub, ph7_class *pBase);
PH7_PRIVATE sxi32 PH7_ClassImplement(ph7_class *pMain, ph7_class *pInterface);
PH7_PRIVATE sxi32 PH7_ClassImplement(ph7_vm *pVm, ph7_class *pMain, ph7_class *pInterface);
PH7_PRIVATE ph7_class_instance *PH7_NewClassInstance(ph7_vm *pVm, ph7_class *pClass);
PH7_PRIVATE ph7_class_instance *PH7_CloneClassInstance(ph7_class_instance *pSrc);
PH7_PRIVATE sxi32 PH7_ClassInstanceCmp(ph7_class_instance *pLeft, ph7_class_instance *pRight, int bStrict, int iNest);

View File

@ -151,7 +151,7 @@ static sxi32 VmJsonEncode(
ph7_context *pCtx = pData->pCtx;
int iFlags = pData->iFlags;
int nByte;
if(ph7_value_is_null(pIn) || ph7_value_is_resource(pIn)) {
if(ph7_value_is_void(pIn) || ph7_value_is_resource(pIn)) {
/* null */
ph7_result_string(pCtx, "null", (int)sizeof("null") - 1);
} else if(ph7_value_is_bool(pIn)) {
@ -620,7 +620,7 @@ static sxi32 VmJsonDecode(
/* Reflect the JSON image */
if(pDecoder->pIn->nType & JSON_TK_NULL) {
/* Nullify the value.*/
ph7_value_null(pWorker);
ph7_value_void(pWorker);
} else if(pDecoder->pIn->nType & (JSON_TK_TRUE | JSON_TK_FALSE)) {
/* Boolean value */
ph7_value_bool(pWorker, (pDecoder->pIn->nType & JSON_TK_TRUE) ? 1 : 0);

28
tests/anon_filter.aer Normal file
View File

@ -0,0 +1,28 @@
class Program {
private callback $condition = bool(int $x) { return ($x > 100); };
private int[] $numbers = {34, 56, 22, 1, 5, 67, 897, 123, 55, 101};
int[] filter(callback $condition, int[] $numbers) {
int $len = sizeof($numbers);
int[] $filtered;
for(int $i = 0; $i < $len; $i++) {
if($condition($numbers[$i])) {
$filtered[] = $numbers[$i];
}
}
return $filtered;
}
void main() {
int[] $filtered = $this->filter($this->condition, $this->numbers);
var_dump($filtered);
}
}
/*
* Should output
Array ( [0] => 897 [1] => 123 )
*/

8
tests/anon_filter.exp Normal file
View File

@ -0,0 +1,8 @@
array(int, 3) {
[0] =>
int(897)
[1] =>
int(123)
[2] =>
int(101)
}

View File

@ -1,21 +1,22 @@
class Program {
private function num2Roman($num) {
$n = intval($num);
$result = '';
$lookup = array('M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400,
private string num2Roman(int $num) {
int $n = $num;
string $result = '';
int[] $lookup = {'M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400,
'C' => 100, 'XC' => 90, 'L' => 50, 'XL' => 40,
'X' => 10, 'IX' => 9, 'V' => 5, 'IV' => 4, 'I' => 1);
'X' => 10, 'IX' => 9, 'V' => 5, 'IV' => 4, 'I' => 1};
int $matches;
foreach($lookup as $roman => $value) {
$matches = intval($n / $value);
$matches = (int) ($n / $value);
$result += str_repeat($roman, $matches);
$n = $n % $value;
}
return $result;
}
public function main() {
public void main() {
print(' 7 => ' + $this->num2Roman(7) + "\n");
print(' 9 => ' + $this->num2Roman(9) + "\n");
print(' 11 => ' + $this->num2Roman(11) + "\n");

19
tests/assertion_test.aer Normal file
View File

@ -0,0 +1,19 @@
class Program {
void test_assert(mixed $param) {
assert("is_bool($param);");
}
void main() {
callback $assert_fail = void(string $file, int $line, string $code) {
print("Assertion failed ...\n");
};
assert_options(ASSERT_ACTIVE, true);
assert_options(ASSERT_BAIL, false);
assert_options(ASSERT_WARNING, false);
assert_options(ASSERT_CALLBACK, $assert_fail);
$this->test_assert(true);
$this->test_assert(1);
}
}

1
tests/assertion_test.exp Normal file
View File

@ -0,0 +1 @@
Assertion failed ...

17
tests/bin_format.aer Normal file
View File

@ -0,0 +1,17 @@
class Program {
string fmt_binary(int $x, int $numbits = 8) {
string $bin;
string $rtnval = '';
$bin = decbin($x);
$bin = substr(str_repeat(0, $numbits), 0, $numbits - strlen($bin)) + $bin;
for($x = 0; $x < $numbits / 4; $x++) {
$rtnval += ' ' + substr($bin, $x * 4, 4);
}
return ltrim($rtnval);
}
void main() {
var_dump($this->fmt_binary(2541));
}
}

1
tests/bin_format.exp Normal file
View File

@ -0,0 +1 @@
string(9 '0000 1001')

View File

@ -0,0 +1,107 @@
class Brainfuck {
private string $code;
private int $code_pointer;
private int[] $cells;
private int $pointer;
private string $input;
private int $input_pointer;
private int[] $buffer;
private string $output;
public void __construct(string $code, string $input = NULL) {
$this->code = $code;
$this->input = $input;
}
public void run() {
while ($this->code_pointer < strlen($this->code)) {
$this->interpret($this->code[$this->code_pointer]);
$this->code_pointer++;
}
print($this->output);
}
private void interpret(string $command) {
if(!$this->cells[$this->pointer]) {
$this->cells[$this->pointer] = 0;
}
switch ($command) {
case '>' :
$this->pointer++;
break;
case '<' :
$this->pointer--;
break;
case '+' :
$this->cells[$this->pointer]++;
if($this->cells[$this->pointer] > 255) {
$this->cells[$this->pointer] = 0;
}
break;
case '-' :
$this->cells[$this->pointer]--;
if($this->cells[$this->pointer] < 0) {
$this->cells[$this->pointer] = 255;
}
break;
case '.' :
$this->output += chr($this->cells[$this->pointer]);
break;
case ',' :
$this->cells[$this->pointer] = $this->input[$this->input_pointer] ? ord($this->input[$this->input_pointer]) : 0;
$this->input_pointer++;
break;
case '[' :
if($this->cells[$this->pointer] == 0) {
int $delta = 1;
while($delta && $this->code_pointer++ < strlen($this->code)) {
switch ($this->code[$this->code_pointer]) {
case '[' :
$delta++;
break;
case ']' :
$delta--;
break;
}
}
} else {
$this->buffer[] = $this->code_pointer;
}
break;
case ']' :
$this->code_pointer = array_pop($this->buffer) - 1;
}
}
}
class Program {
void main() {
object $bf;
string $code;
resource $dir;
string $file;
string[] $files;
string $input;
$dir = opendir('tests/data/brainfuck');
while($file = readdir($dir)) {
if($file == '.' || $file == '..') {
continue;
}
$files[] = $file;
}
sort($files);
unset($file);
foreach($files as $file) {
print('Executing "' + $file + '"' + "\n");
$code = file_get_contents('tests/data/brainfuck/' + $file);
$bf = new Brainfuck($code, $input);
$bf->run();
print("\n");
}
closedir($dir);
}
}

View File

@ -0,0 +1,39 @@
Executing "array.bf"
EC
Executing "hello_world.bf"
Hello World!
Executing "sierpinski.bf"
*
* *
* *
* * * *
* *
* * * *
* * * *
* * * * * * * *
* *
* * * *
* * * *
* * * * * * * *
* * * *
* * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * *
* *
* * * *
* * * *
* * * * * * * *
* * * *
* * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * *
* * * *
* * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

View File

@ -0,0 +1,15 @@
class Program {
void main(string[] $args) {
callback $y = void() {
callback $a = 'printf';
$a("I'm alive\n");
var_dump($a);
};
$y();
var_dump($y);
string $a = 'printf';
var_dump($a);
}
}

View File

@ -0,0 +1,4 @@
I'm alive
callback(6 'printf')
callback(11 '{closure_1}')
string(6 'printf')

28
tests/center_text.aer Normal file
View File

@ -0,0 +1,28 @@
class Program {
private string center_text(string $word){
int $tot_width = 30;
char $symbol = '-';
int $middle = (int) round($tot_width/2);
int $length_word = strlen($word);
int $middle_word = (int) round($length_word / 2);
int $last_position = $middle + $middle_word;
int $number_of_spaces = $middle - $middle_word;
string $result = sprintf("%'{$symbol}{$last_position}s", $word);
for(int $i = 0; $i < $number_of_spaces; $i++) {
$result += "$symbol";
}
return $result;
}
void main() {
string $str = 'Example text';
print($this->center_text($str));
}
}
/* Should output
---------------This is some text------------
*/

1
tests/center_text.exp Normal file
View File

@ -0,0 +1 @@
---------Example text---------

View File

@ -0,0 +1,19 @@
class Test1 {
}
class Test2 extends Test1 {
}
class Program {
object $t;
void test(Test1 $t = new Test2) {
$this->t = $t;
var_dump($this->t);
}
void main() {
$this->test();
}
}

View File

@ -0,0 +1,2 @@
object(Test2) {
}

41
tests/closure_event.aer Normal file
View File

@ -0,0 +1,41 @@
class Button {
public callback $OnBeforeClick;
public callback $OnAfterClick;
public string $Name;
public void __construct() {
$this->Name = 'MyButton';
}
public void Click() {
$this->DoBeforeClick();
print('Click!');
$this->DoAfterClick();
}
private void DoBeforeClick() {
if($this->OnBeforeClick) {
callback $event = $this->OnBeforeClick;
$event($this);
}
}
private void DoAfterClick() {
if($this->OnAfterClick) {
callback $event = $this->OnAfterClick;
$event($this);
}
}
}
class Program {
void main() {
object $MyWidget = new Button();
$MyWidget->OnBeforeClick = void(object $Sender) { print($Sender->Name + ' (Before Click)'); };
$MyWidget->OnAfterClick = void(object $Sender) { print($Sender->Name + ' (After Click)'); };
$MyWidget->Click();
}
}

1
tests/closure_event.exp Normal file
View File

@ -0,0 +1 @@
MyButton (Before Click)Click!MyButton (After Click)

36
tests/closure_test.aer Normal file
View File

@ -0,0 +1,36 @@
class Operations {
public callback ops(int $x, int $y, string $op){
switch($op) {
case 'ADD':
return int() using ($x, $y) {
return $x + $y;
};
break;
case 'SUB':
return int() using ($x, $y) {
return $x - $y;
};
break;
default:
return string() {
return 'Operation is not supported by class.';
};
}
}
}
class Program {
void main() {
callback $fn;
object $op = new Operations();
$fn = $op->ops(6, 7, 'ADD');
print($fn() + "\n");
$fn = $op->ops(6, 2, 'SUB');
print($fn() + "\n");
$fn = $op->ops(6, 7, 'MUL');
print($fn() + "\n");
}
}

3
tests/closure_test.exp Normal file
View File

@ -0,0 +1,3 @@
13
4
Operation is not supported by class.

View File

@ -0,0 +1,43 @@
class Program {
private const MY_CONST = 12 ^ 0x3FD;
private callback $callback_test = void(){ print("Welcome everyone!\n");};
private static int $value = 4 + 4 * 4;
void callable(callback $callback = void(){ print("Hello world!\n");}) {
$callback();
}
void complexArgs(string $name = 'AerScript' + $this->someStr(), int $age = 10*2+5) {
print("Name = $name\n");
print("Age = $age\n");
}
string someStr() {
return 'ABC';
}
bool someTrue() {
return true;
}
bool someFalse() {
return false;
}
int main() {
static float $f = 4 + 2.4 * 9.1;
var_dump($this->MY_CONST);
var_dump($this->callback_test);
var_dump($this->value);
var_dump($f);
$this->complexArgs();
$this->complexArgs('Me');
$this->callable();
$this->callable(void(){ print("Welcome guest!\n");});
$this->callable($this->callback_test);
$this->someTrue() || print("someTrue() failed\n");
$this->someFalse() || print("someFalse() failed\n");
return 0;
}
}

View File

@ -0,0 +1,12 @@
int(1009)
callback(11 '{closure_1}')
int(20)
float(25.84)
Name = AerScriptABC
Age = 25
Name = Me
Age = 25
Hello world!
Welcome guest!
Welcome everyone!
someFalse() failed

View File

@ -0,0 +1,16 @@
class Program {
void test(int $a = (int(int $a, int $b, int $c){return $a+$b+$c;})(14, 10+2, 15), int $b = 0, int $c = 98) {
print($a + PHP_EOL);
print($b + PHP_EOL);
print($c + PHP_EOL);
}
void main() {
$this->test();
$this->test(512);
$this->test(1024, 32);
$this->test(1000, 2000, 4000);
}
}

View File

@ -0,0 +1,12 @@
41
0
98
512
0
98
1024
32
98
1000
2000
4000

View File

@ -0,0 +1,22 @@
>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>
>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>
>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>
>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>
>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>
<<<<<<<<<<
first put the desired index in front of the array
++++
we are done if there is a zero in the current tag cell
[
decrement the current tag cell
-
move the value in the current tag cell to the next if it is not zero
[>>+<<-]
move to next tag cell
>>
we found it: print the desired element
]>.
now print another
<<<<<<<<<
++
[-[>>+<<-]>>]>.

View File

@ -0,0 +1 @@
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.

View File

@ -0,0 +1,5 @@
++++++++[>+>++++<<-]>++>>+<[-[>>+<<-]+>>]>+[
-<<<[
->[+[-]+>++>>>-<<]<[<]>>++++++[<<+++++>>-]+<<++.[-]<<
]>.>+[>>]>+
]

View File

@ -1,12 +1,12 @@
class Program {
function main() {
void main() {
$this->b($this->a('First A'), $this->a('Second A'), $this->a('Third A'));
}
function a($p) {
$backtrace = debug_backtrace();
if(isset($backtrace[0]['args'])) {
string a(string $p) {
mixed[] $backtrace = debug_backtrace();
if(array_key_exists('args', $backtrace[0])) {
var_export($backtrace[0]['args']);
} else {
print("Cannot aquire arguments\n");
@ -14,7 +14,7 @@ class Program {
return $p;
}
function b($p1, $p2, $p3) {
void b(string $p1, string $p2, string $p3) {
print("$p1, $p2, $p3");
}

View File

@ -0,0 +1,33 @@
class ExceptionHandler {
public static void printException(Exception $e) {
print('Uncaught ' + get_class($e) + ', code: ' + $e->getCode() + "\nMessage: " + htmlentities($e->getMessage()) + "\n");
}
public static void handleException(Exception $e) {
self::printException($e);
}
}
class NewException extends Exception {
}
class Program {
void main() {
callback $handler = void(Exception $e) {
ExceptionHandler::handleException($e);
};
set_exception_handler($handler);
try {
throw new NewException("Catch me once", 1);
} catch(Exception $e) {
ExceptionHandler::handleException($e);
}
throw new Exception("Catch me twice", 2);
}
}

View File

@ -0,0 +1,4 @@
Uncaught NewException, code: 1
Message: Catch me once
Uncaught Exception, code: 2
Message: Catch me twice

View File

@ -0,0 +1,24 @@
class Dog {
public string $name;
public string $color;
public void __construct(string $name, string $color) {
$this->name = $name;
$this->color = $color;
}
public callback greet(string $greeting) {
return void() using ($greeting) {
print("$greeting, I am a {$this->color} dog named {$this->name}\n");
};
}
}
class Program {
void main() {
object $dog = new Dog('Alex', 'red');
callback $c = $dog->greet('Hello');
$c();
}
}

View File

@ -0,0 +1 @@
Hello, I am a red dog named Alex

15
tests/factorial_test.aer Normal file
View File

@ -0,0 +1,15 @@
class Program {
int factorial(int $num) {
if($num == 0 || $num == 1)
return 1;
else
return $num * $this->factorial($num - 1);
}
void main() {
int $num = 7;
print('Factorial of ', $num, ' is ', $this->factorial($num), '.');
}
}

1
tests/factorial_test.exp Normal file
View File

@ -0,0 +1 @@
Factorial of 7 is 5040.

29
tests/factory_objects.aer Normal file
View File

@ -0,0 +1,29 @@
class Circle {
void draw() {
print("Circle\n");
}
}
class Square {
void draw() {
print("Square\n");
}
}
class Program {
object ShapeFactoryMethod(string $shape) {
switch ($shape) {
case "Circle":
return new Circle();
case "Square":
return new Square();
}
}
void main() {
$this->ShapeFactoryMethod("Circle")->draw();
$this->ShapeFactoryMethod("Square")->draw();
}
}

View File

@ -0,0 +1,2 @@
Circle
Square

View File

@ -1,7 +1,12 @@
#!/usr/local/bin/aer
class Program {
public function main() {
print('Hello world!');
/*
* Program entry point.
* It does not take any arguments.
*/
public void main() {
print('Hello world!'); // single line comment
}
}

26
tests/int2alpha_test.aer Normal file
View File

@ -0,0 +1,26 @@
class Program {
string num2alpha(int $n) {
string $r = '';
for(int $i = 1; $n >= 0 && $i < 10; $i++) {
$r = chr(0x41 + ($n % pow(26, $i) / pow(26, $i - 1))) + $r;
$n -= pow(26, $i);
}
return $r;
}
int alpha2num(string $a) {
int $r = 0;
int $l = strlen($a);
for(int $i = 0; $i < $l; $i++) {
$r += pow(26, $i) * (ord($a[$l - $i - 1]) - 0x40);
}
return (int) $r - 1;
}
void main() {
import('math');
var_dump($this->alpha2num("Salut"), $this->num2alpha(1723), $this->num2alpha(9854), $this->alpha2num("Base64"));
}
}

4
tests/int2alpha_test.exp Normal file
View File

@ -0,0 +1,4 @@
int(9293725)
string(3 'BNH')
string(3 'NOA')
int(39764075)

42
tests/interface_test.aer Normal file
View File

@ -0,0 +1,42 @@
interface iVehicle {
public void drive();
public void stop();
}
class Car implements iVehicle {
public void drive() {
print("Driving...\n");
}
public void stop() {
print("Stopping...\n");
}
}
class MyCar extends Car {
public void drive() {
print("Driving my car...\n");
}
}
class Program {
public void driveCar(iVehicle $vehicle) {
$vehicle->drive();
$vehicle->stop();
}
public void main() {
object $car = new Car();
object $mycar = new MyCar();
$this->driveCar($car);
$this->driveCar($mycar);
}
}

4
tests/interface_test.exp Normal file
View File

@ -0,0 +1,4 @@
Driving...
Stopping...
Driving my car...
Stopping...

22
tests/ip_addr_enc_dec.aer Normal file
View File

@ -0,0 +1,22 @@
class Program {
string encode_ip(string $dotquad_ip) {
string[] $ip_sep = explode('.', $dotquad_ip);
return sprintf('%02x%02x%02x%02x', $ip_sep[0], $ip_sep[1], $ip_sep[2], $ip_sep[3]);
}
string decode_ip(string $int_ip) {
string[] $hexipbang = explode('.', chunk_split($int_ip, 2, '.'));
return hexdec($hexipbang[0]) + '.' + hexdec($hexipbang[1]) + '.' + hexdec($hexipbang[2]) + '.' + hexdec($hexipbang[3]);
}
void main() {
string $localhost = $this->encode_ip('127.0.0.1');
print("127.0.0.1 ==> $localhost\n");
string $router = $this->encode_ip('192.168.2.1');
print("192.168.2.1 ==> $router\n");
print("$localhost ==> ", $this->decode_ip($localhost) + PHP_EOL);
print("$router ==> ", $this->decode_ip($router) + PHP_EOL);
}
}

View File

@ -0,0 +1,4 @@
127.0.0.1 ==> 7f000001
192.168.2.1 ==> c0a80201
7f000001 ==> 127.0.0.1
c0a80201 ==> 192.168.2.1

View File

@ -1,5 +1,5 @@
final class Program {
function main() {
void main() {
var_dump(function_exists('dummy_function'));
var_dump(import('dummy'));
var_dump(function_exists('dummy_function'));

View File

@ -0,0 +1,23 @@
class Program {
private int test() {
static int $x = 9;
return $x--;
}
public void main() {
int $a;
do {
$a = $this->test();
int $z = $a;
if($z == 6) {
continue;
} else if($z == 3) {
break;
}
print("$z\n");
} while($a);
print("$a\n");
}
}

View File

@ -0,0 +1,6 @@
9
8
7
5
4
3

20
tests/loop_for_test.aer Normal file
View File

@ -0,0 +1,20 @@
class Program {
public void main() {
int $c = 4;
for(int $a = 0; $a < 10; $a++) {
for(int $b = 0; $b < 10; $b++) {
int $c = 2;
if($b == 2) {
continue;
}
if($b == 6) {
break;
}
print("Hello variables: $a $b $c\n");
}
}
print("Variable \$c: $c\n");
}
}

51
tests/loop_for_test.exp Normal file
View File

@ -0,0 +1,51 @@
Hello variables: 0 0 2
Hello variables: 0 1 2
Hello variables: 0 3 2
Hello variables: 0 4 2
Hello variables: 0 5 2
Hello variables: 1 0 2
Hello variables: 1 1 2
Hello variables: 1 3 2
Hello variables: 1 4 2
Hello variables: 1 5 2
Hello variables: 2 0 2
Hello variables: 2 1 2
Hello variables: 2 3 2
Hello variables: 2 4 2
Hello variables: 2 5 2
Hello variables: 3 0 2
Hello variables: 3 1 2
Hello variables: 3 3 2
Hello variables: 3 4 2
Hello variables: 3 5 2
Hello variables: 4 0 2
Hello variables: 4 1 2
Hello variables: 4 3 2
Hello variables: 4 4 2
Hello variables: 4 5 2
Hello variables: 5 0 2
Hello variables: 5 1 2
Hello variables: 5 3 2
Hello variables: 5 4 2
Hello variables: 5 5 2
Hello variables: 6 0 2
Hello variables: 6 1 2
Hello variables: 6 3 2
Hello variables: 6 4 2
Hello variables: 6 5 2
Hello variables: 7 0 2
Hello variables: 7 1 2
Hello variables: 7 3 2
Hello variables: 7 4 2
Hello variables: 7 5 2
Hello variables: 8 0 2
Hello variables: 8 1 2
Hello variables: 8 3 2
Hello variables: 8 4 2
Hello variables: 8 5 2
Hello variables: 9 0 2
Hello variables: 9 1 2
Hello variables: 9 3 2
Hello variables: 9 4 2
Hello variables: 9 5 2
Variable $c: 4

23
tests/loop_while_test.aer Normal file
View File

@ -0,0 +1,23 @@
class Program {
private int test() {
static int $x = 9;
return $x--;
}
public void main() {
int $a;
int $b = 2;
while($a = $this->test()) {
int $b = $a;
if($b == 6) {
continue;
} else if($b == 3) {
break;
}
print("$b\n");
}
print("$b\n");
}
}

View File

@ -0,0 +1,6 @@
9
8
7
5
4
2

44
tests/luhn_verify.aer Normal file
View File

@ -0,0 +1,44 @@
class Luhn {
private string $number;
string getNumber() {
return $this->number;
}
void setNumber(string $number) {
$this->number = $number;
}
bool validate() {
string $sum;
string $revNumber;
int $len;
$revNumber = strrev($this->number);
$len = strlen($this->number);
for(int $i = 0; $i < $len; $i++) {
$sum += $i & 1 ? $revNumber[$i] * 2 : $revNumber[$i];
}
return array_sum(str_split($sum)) % 10 == 0;
}
}
class Program {
private const NUMBERS = {'3788803280', '6487308345', '5443489710530865', '5539266155200609', '4024007151066296', '4345234978'};
void main() {
int $i, $nums = sizeof($this->NUMBERS);
object $luhn = new Luhn();
while($i < $nums) {
$luhn->setNumber($this->NUMBERS[$i]);
if($luhn->validate()) {
print('The number ' + $luhn->getNumber() + ' has passed the Luhn validation.' + "\n");
} else {
print('The number ' + $luhn->getNumber() + ' has NOT passed the Luhn validation.' + "\n");
}
$i++;
}
}
}

6
tests/luhn_verify.exp Normal file
View File

@ -0,0 +1,6 @@
The number 3788803280 has passed the Luhn validation.
The number 6487308345 has passed the Luhn validation.
The number 5443489710530865 has passed the Luhn validation.
The number 5539266155200609 has passed the Luhn validation.
The number 4024007151066296 has passed the Luhn validation.
The number 4345234978 has NOT passed the Luhn validation.

16
tests/magic_method.aer Normal file
View File

@ -0,0 +1,16 @@
class Dog {
void __invoke() {
print("I am a dog!\n");
}
}
class Program {
void main() {
object $dog = new Dog();
$dog();
}
}

1
tests/magic_method.exp Normal file
View File

@ -0,0 +1 @@
I am a dog!

View File

@ -0,0 +1,62 @@
interface IntA {
public void test_a();
}
interface IntB {
public void test_b();
}
class TestA {
public void test_a() {
print("Hello world from TestA::test_a().\n");
}
}
class TestB {
public void test_b() {
print("Hello world from TestB::test_b().\n");
}
}
class TestC {
public void test_c() {
print("Hello world from TestC::test_c().\n");
}
}
class TestD {
public void test_a() {
print("Hello world from TestD::test_a().\n");
}
}
class TestE {
public void test_b() {
print("Hello world from TestE::test_b().\n");
}
}
class Program extends TestE, TestD, TestC, TestB, TestA implements IntA, IntB {
void main() {
$this->test_a();
$this->test_b();
$this->test_c();
}
}

View File

@ -0,0 +1,3 @@
Hello world from TestD::test_a().
Hello world from TestE::test_b().
Hello world from TestC::test_c().

View File

@ -0,0 +1,20 @@
class Program {
string[] testArray() {
return {'Machine' => 'Turing'};
}
callback[] testCallback() {
return {'callme' => void() { print("Hello world\n"); }};
}
void main() {
callback[] $constr = {'print'};
print($this->testArray()['Machine'] + "\n");
$this->testCallback()['callme']();
print(true ? "TRUE\n" : false ? "true\n" : "false\n");
(void(string $name) { print("This should work too - $name.\n");})('AerScript');
$constr[0]('Test finished.' + "\n");
}
}

View File

@ -0,0 +1,5 @@
Turing
Hello world
TRUE
This should work too - AerScript.
Test finished.

View File

@ -0,0 +1,16 @@
class Program {
void count(int $a, int $b) {
print("Counting 2 integers: $a + $b = ", $a + $b, "\n");
}
void count(float $a, float $b) {
print("Counting 2 floats: $a + $b = ", $a + $b, "\n");
}
void main() {
$this->count(4.3, 5.7);
$this->count(6, 4);
}
}

View File

@ -0,0 +1,2 @@
Counting 2 floats: 4.3 + 5.7 = 10
Counting 2 integers: 6 + 4 = 10

32
tests/path_split.aer Normal file
View File

@ -0,0 +1,32 @@
class Program {
string[] parsePathComponents(string $path, bool $endSlash=true, bool $base=false) {
string[] $retArray;
$path = trim($path);
string $str, $temp;
char $char;
for(int $x = 0; $char = $path[$x]; $x++) {
if(!strstr('/', $char)) $temp += $char;
else if($temp) {
$str += $temp;
$retArray[$temp] = $str + ($endSlash ? '/' : '');
$str += '/';
$temp = '';
}
}
($base && $temp) ? $retArray[$temp] = $str + $temp : NULL;
return $retArray;
}
void main() {
string $path = '/my//stupid//path/to///some/file.php';
print_r($this->parsePathComponents($path));
$path = 'my/other//path/';
print_r($this->parsePathComponents($path, false));
$path = '/my//other/path/to///file.php';
print_r($this->parsePathComponents($path, true, true));
}
}

32
tests/path_split.exp Normal file
View File

@ -0,0 +1,32 @@
Array(5) {
[my] =>
my/
[stupid] =>
my/stupid/
[path] =>
my/stupid/path/
[to] =>
my/stupid/path/to/
[some] =>
my/stupid/path/to/some/
}
Array(3) {
[my] =>
my
[other] =>
my/other
[path] =>
my/other/path
}
Array(5) {
[my] =>
my/
[other] =>
my/other/
[path] =>
my/other/path/
[to] =>
my/other/path/to/
[file.php] =>
my/other/path/to/file.php
}

View File

@ -1,16 +1,16 @@
class Program {
private $s = 'monkey';
private $t = 'many monkeys';
private $n = 43951789;
private $u = -43951789;
private $c = 65;
private string $s = 'monkey';
private string $t = 'many monkeys';
private int $n = 43951789;
private int $u = -43951789;
private char $c = 65;
public function main() {
public void main() {
$this->testMonkey();
$this->testNumbers();
}
private function testMonkey() {
private void testMonkey() {
printf("[%s]\n", $this->s);
printf("[%10s]\n", $this->s);
printf("[%-10s]\n", $this->s);
@ -19,9 +19,10 @@ class Program {
printf("[%10.10s]\n", $this->t);
}
private function testNumbers() {
private void testNumbers() {
printf("%%b = '%b'\n", $this->n);
printf("%%c = '%c'\n", $this->c);
printf("%%d = '%d'\n", $this->c);
printf("%%d = '%d'\n", $this->n);
printf("%%e = '%e'\n", $this->n);
printf("%%u = '%u'\n", $this->n);

View File

@ -6,6 +6,7 @@
[many monke]
%b = '10100111101010011010101101'
%c = 'A'
%d = '65'
%d = '43951789'
%e = '4.395179e+07'
%u = '43951789'

13
tests/reference_test.aer Normal file
View File

@ -0,0 +1,13 @@
class Program {
void add_by_ref(int &$val) {
$val += 7;
}
void main() {
int $num = 7;
$this->add_by_ref($num);
var_dump($num);
}
}

1
tests/reference_test.exp Normal file
View File

@ -0,0 +1 @@
int(14)

View File

@ -1,32 +1,32 @@
final class Test {
private $value;
private int $value;
private function __construct() {
private void __construct() {
}
/* This is singleton */
public function getInstance() {
static $instance;
public object getInstance() {
static object $instance;
if(!$instance) {
$instance = new Test();
}
return $instance;
}
public function get() {
public int get() {
return $this->value;
}
public function set($value = 0) {
public int set(int $value = 0) {
$this->value = $value;
}
}
final class Program {
public function main() {
$testA = Test::getInstance();
public void main() {
object $testA = Test::getInstance();
$testA->set(5);
$testB = Test::getInstance();
object $testB = Test::getInstance();
var_dump($testB->get());
}
} /* class */

24
tests/static_var.aer Normal file
View File

@ -0,0 +1,24 @@
class Program {
string cycle(char $a, char $b, int $i = 0) {
static char[] $switches;
if($switches[$i])
$switches[$i] = !$switches[$i];
else
!($switches[$i] = true);
return ($switches[$i]) ? $a : $b;
}
void main() {
for(int $i = 1; $i < 3; $i++) {
print($i + $this->cycle('a', 'b') + PHP_EOL);
for(int $j = 1; $j < 5; $j++) {
print(' ' + $j + $this->cycle('a', 'b', 1) + PHP_EOL);
for(int $k = 1; $k < 3; $k++) {
print(' ' + $k + $this->cycle('c', 'd', 2) + PHP_EOL);
}
}
}
}
}

26
tests/static_var.exp Normal file
View File

@ -0,0 +1,26 @@
1a
1a
1c
2d
2b
1c
2d
3a
1c
2d
4b
1c
2d
2b
1a
1c
2d
2b
1c
2d
3a
1c
2d
4b
1c
2d

20
tests/switch_block.aer Normal file
View File

@ -0,0 +1,20 @@
class Program {
void main() {
int $a = 1;
switch($a) {
case 0:
print("very bad\n");
break;
case 1:
print("very good\n");
case 2:
print("good\n");
break;
default:
print("bad");
break;
}
}
}

2
tests/switch_block.exp Normal file
View File

@ -0,0 +1,2 @@
very good
good

21
tests/text_normalize.aer Normal file
View File

@ -0,0 +1,21 @@
class Program {
string normalize(string $str) {
string[] $table = {
'Š'=>'S', 'š'=>'s', 'Đ'=>'Dj', 'đ'=>'dj', 'Ž'=>'Z', 'ž'=>'z', 'Č'=>'C', 'č'=>'c', 'Ć'=>'C', 'ć'=>'c',
'À'=>'A', 'Á'=>'A', 'Â'=>'A', 'Ã'=>'A', 'Ä'=>'A', 'Å'=>'A', 'Æ'=>'A', 'Ç'=>'C', 'È'=>'E', 'É'=>'E',
'Ê'=>'E', 'Ë'=>'E', 'Ì'=>'I', 'Í'=>'I', 'Î'=>'I', 'Ï'=>'I', 'Ñ'=>'N', 'Ò'=>'O', 'Ó'=>'O', 'Ô'=>'O',
'Õ'=>'O', 'Ö'=>'O', 'Ø'=>'O', 'Ù'=>'U', 'Ú'=>'U', 'Û'=>'U', 'Ü'=>'U', 'Ý'=>'Y', 'Þ'=>'B', 'ß'=>'Ss',
'à'=>'a', 'á'=>'a', 'â'=>'a', 'ã'=>'a', 'ä'=>'a', 'å'=>'a', 'æ'=>'a', 'ç'=>'c', 'è'=>'e', 'é'=>'e',
'ê'=>'e', 'ë'=>'e', 'ì'=>'i', 'í'=>'i', 'î'=>'i', 'ï'=>'i', 'ð'=>'o', 'ñ'=>'n', 'ò'=>'o', 'ó'=>'o',
'ô'=>'o', 'õ'=>'o', 'ö'=>'o', 'ø'=>'o', 'ù'=>'u', 'ú'=>'u', 'û'=>'u', 'ý'=>'y', 'ý'=>'y', 'þ'=>'b',
'ÿ'=>'y', 'Ŕ'=>'R', 'ŕ'=>'r'
};
return strtr($str, $table);
}
void main() {
var_dump($this->normalize("ÿĆ Welcome ÂëÑ Žöø Ŕ"));
}
}

1
tests/text_normalize.exp Normal file
View File

@ -0,0 +1 @@
string(20 'yC Welcome AeN Zoo R')

36
tests/tokenizer.aer Normal file
View File

@ -0,0 +1,36 @@
class StringTokenizer {
private string $token;
private string $delim;
public void __construct(string $str, string $delim = ' ') {
$this->token = strtok($str, $delim);
$this->delim = $delim;
}
public void __destruct() {
unset($this);
}
public bool hasMoreTokens() {
return ($this->token != NULL);
}
public string nextToken() {
string $current = $this->token;
$this->token = strtok($this->delim);
return $current;
}
}
class Program {
void main() {
string $str = "This is:@\t\n a TEST!";
string $delim = " !@:\t\n";
object $st = new StringTokenizer($str, $delim);
while ($st->hasMoreTokens()) {
print($st->nextToken(), "\n");
}
unset($st);
}
}

4
tests/tokenizer.exp Normal file
View File

@ -0,0 +1,4 @@
This
is
a
TEST

43
tests/type_hinting.aer Normal file
View File

@ -0,0 +1,43 @@
class Program {
private int $test = 7;
void testChar(char $value) {
var_dump($value);
var_dump(is_char($value));
}
void testFloat(float $value) {
var_dump($value);
var_dump(is_float($value));
}
void testObject(object $value) {
var_dump($value);
var_dump(is_object($value));
}
void testString(string $value) {
var_dump($value);
var_dump(is_string($value));
}
void testVoid(void $value) {
var_dump($value);
var_dump(is_void($value));
}
void main() {
object $objval;
void $voidval;
$this->testChar('c');
$this->testChar(NULL);
$this->testFloat(4);
$this->testFloat(56.3);
$this->testObject($objval);
$this->testObject($this);
$this->testString('sample text');
$this->testString(NULL);
$this->testVoid($voidval);
$this->testVoid(NULL);
}
}

23
tests/type_hinting.exp Normal file
View File

@ -0,0 +1,23 @@
char(c)
bool(TRUE)
char()
bool(TRUE)
float(4)
bool(TRUE)
float(56.3)
bool(TRUE)
object()
bool(TRUE)
object(Program) {
['test'] =>
int(7)
}
bool(TRUE)
string(11 'sample text')
bool(TRUE)
string(0 '')
bool(TRUE)
void(NULL)
bool(TRUE)
void(NULL)
bool(TRUE)

View File

@ -1,6 +1,7 @@
class Program {
function main() {
void main() {
mixed $foo;
$foo = '0';
var_dump($foo);
$foo += 2;

View File

@ -1,7 +1,8 @@
class Unicode {
public function unicon($str, $to_uni = true) {
$cp = array('А' => '&#x410;', 'а' => '&#x430;',
public string unicon(string $str, bool $to_uni = true) {
string $cpp;
string[] $cp = {'А' => '&#x410;', 'а' => '&#x430;',
"Б" => "&#x411;", "б" => "&#x431;",
"В" => "&#x412;", "в" => "&#x432;",
"Г" => "&#x413;", "г" => "&#x433;",
@ -33,7 +34,7 @@ class Unicode {
"Ь" => "&#x42C;", "ь" => "&#x44C;",
"Э" => "&#x42D;", "э" => "&#x44D;",
"Ю" => "&#x42E;", "ю" => "&#x44E;",
"Я" => "&#x42F;", "я" => "&#x44F;");
"Я" => "&#x42F;", "я" => "&#x44F;"};
if($to_uni) {
$str = strtr($str, $cp);
} else {
@ -49,8 +50,8 @@ class Unicode {
final class Program {
public function main() {
$unicode = new Unicode();
public void main() {
object $unicode = new Unicode();
var_dump($unicode->unicon("ИфйжБЦ"));
}

View File

@ -1,33 +1,33 @@
class Program {
private $概要 = "AerScript Interpreter";
private string $概要 = "AerScript Interpreter";
public function main() {
public void main() {
$this->ダウンロード();
var_dump($this->概要);
var_dump($this->isUTF8('hello'));
var_dump($this->isUTF8("すが、基本的な使い方は単純です。かしながら使い方を身につけていきましょう"));
}
private function ダウンロード(){
private void ダウンロード(){
print($this->概要 + "\n");
}
private function isUTF8($str) {
$b = 0;
$c = 0;
$bits = 0;
$len = strlen($str);
for($i = 0; $i < $len; $i++) {
private bool isUTF8(string $str) {
int $b = 0;
int $c = 0;
int $bits = 0;
int $len = strlen($str);
for(int $i = 0; $i < $len; $i++) {
$c = ord($str[$i]);
if($c >= 128) {
if(($c >= 254)) return false;
elseif($c >= 252) $bits=6;
elseif($c >= 248) $bits=5;
elseif($c >= 240) $bits=4;
elseif($c >= 224) $bits=3;
elseif($c >= 192) $bits=2;
else if($c >= 252) $bits=6;
else if($c >= 248) $bits=5;
else if($c >= 240) $bits=4;
else if($c >= 224) $bits=3;
else if($c >= 192) $bits=2;
else return false;
if(($i+$bits) > $len) return false;
if(($i + $bits) > $len) return false;
while($bits > 1) {
$i++;
$b=ord($str[$i]);