Refactor foreach() loop.
The build was successful.
Details
The build was successful.
Details
In AerScript, the foreach() loop is syntatically more similiar to C#, than PHP. However the optional '$key => $value' construct is still available, because arrays in AerScript are still a hashmaps.
This commit is contained in:
parent
1156519af6
commit
4d8d92092e
|
@ -1789,12 +1789,12 @@ static sxi32 GenStateForEachNodeValidator(ph7_gen_state *pGen, ph7_expr_node *pR
|
||||||
/*
|
/*
|
||||||
* Compile the 'foreach' statement.
|
* Compile the 'foreach' statement.
|
||||||
* The foreach construct simply gives an easy way to iterate over arrays. foreach works
|
* The foreach construct simply gives an easy way to iterate over arrays. foreach works
|
||||||
* only on arrays (and objects), and will issue an error when you try to use it on a variable
|
* only on arrays, and will issue an error when you try to use it on a variable
|
||||||
* with a different data type or an uninitialized variable. There are two syntaxes; the second
|
* with a different data type or an uninitialized variable. There are two syntaxes; the second
|
||||||
* is a minor but useful extension of the first:
|
* is a minor but useful extension of the first:
|
||||||
* foreach (array_expression as $value)
|
* foreach ($value in array_expression)
|
||||||
* statement
|
* statement
|
||||||
* foreach (array_expression as $key => $value)
|
* foreach ($key => $value in array_expression)
|
||||||
* statement
|
* statement
|
||||||
* The first form loops over the array given by array_expression. On each loop, the value
|
* The first form loops over the array given by array_expression. On each loop, the value
|
||||||
* of the current element is assigned to $value and the internal array pointer is advanced
|
* of the current element is assigned to $value and the internal array pointer is advanced
|
||||||
|
@ -1804,12 +1804,6 @@ static sxi32 GenStateForEachNodeValidator(ph7_gen_state *pGen, ph7_expr_node *pR
|
||||||
* Note:
|
* Note:
|
||||||
* When foreach first starts executing, the internal array pointer is automatically reset to the
|
* When foreach first starts executing, the internal array pointer is automatically reset to the
|
||||||
* first element of the array. This means that you do not need to call reset() before a foreach loop.
|
* first element of the array. This means that you do not need to call reset() before a foreach loop.
|
||||||
* Note:
|
|
||||||
* Unless the array is referenced, foreach operates on a copy of the specified array and not the array
|
|
||||||
* itself. foreach has some side effects on the array pointer. Don't rely on the array pointer during
|
|
||||||
* or after the foreach without resetting it.
|
|
||||||
* You can easily modify array's elements by preceding $value with &. This will assign reference instead
|
|
||||||
* of copying the value.
|
|
||||||
*/
|
*/
|
||||||
static sxi32 PH7_CompileForeach(ph7_gen_state *pGen) {
|
static sxi32 PH7_CompileForeach(ph7_gen_state *pGen) {
|
||||||
SyToken *pCur, *pTmp, *pEnd = 0;
|
SyToken *pCur, *pTmp, *pEnd = 0;
|
||||||
|
@ -1839,40 +1833,6 @@ static sxi32 PH7_CompileForeach(ph7_gen_state *pGen) {
|
||||||
/* Empty expression */
|
/* Empty expression */
|
||||||
PH7_GenCompileError(pGen, E_ERROR, nLine, "foreach: Missing expression");
|
PH7_GenCompileError(pGen, E_ERROR, nLine, "foreach: Missing expression");
|
||||||
}
|
}
|
||||||
/* Compile the array expression */
|
|
||||||
pCur = pGen->pIn;
|
|
||||||
while(pCur < pEnd) {
|
|
||||||
if(pCur->nType & PH7_TK_KEYWORD) {
|
|
||||||
sxi32 nKeywrd = SX_PTR_TO_INT(pCur->pUserData);
|
|
||||||
if(nKeywrd == PH7_KEYWORD_AS) {
|
|
||||||
/* Break with the first 'as' found */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Advance the stream cursor */
|
|
||||||
pCur++;
|
|
||||||
}
|
|
||||||
if(pCur <= pGen->pIn) {
|
|
||||||
PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine,
|
|
||||||
"foreach: Missing array/object expression");
|
|
||||||
}
|
|
||||||
/* Swap token streams */
|
|
||||||
pTmp = pGen->pEnd;
|
|
||||||
pGen->pEnd = pCur;
|
|
||||||
rc = PH7_CompileExpr(&(*pGen), 0, 0);
|
|
||||||
if(rc == SXERR_ABORT) {
|
|
||||||
/* Expression handler request an operation abort [i.e: Out-of-memory] */
|
|
||||||
return SXERR_ABORT;
|
|
||||||
}
|
|
||||||
/* Update token stream */
|
|
||||||
if(pGen->pIn < pCur) {
|
|
||||||
PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "foreach: Unexpected token '%z'", &pGen->pIn->sData);
|
|
||||||
}
|
|
||||||
pCur++; /* Jump the 'as' keyword */
|
|
||||||
pGen->pIn = pCur;
|
|
||||||
if(pGen->pIn >= pEnd) {
|
|
||||||
PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "foreach: Missing $key => $value pair");
|
|
||||||
}
|
|
||||||
/* Create the foreach context */
|
/* Create the foreach context */
|
||||||
pInfo = (ph7_foreach_info *)SyMemBackendAlloc(&pGen->pVm->sAllocator, sizeof(ph7_foreach_info));
|
pInfo = (ph7_foreach_info *)SyMemBackendAlloc(&pGen->pVm->sAllocator, sizeof(ph7_foreach_info));
|
||||||
if(pInfo == 0) {
|
if(pInfo == 0) {
|
||||||
|
@ -1882,43 +1842,55 @@ static sxi32 PH7_CompileForeach(ph7_gen_state *pGen) {
|
||||||
SyZero(pInfo, sizeof(ph7_foreach_info));
|
SyZero(pInfo, sizeof(ph7_foreach_info));
|
||||||
/* Initialize structure fields */
|
/* Initialize structure fields */
|
||||||
SySetInit(&pInfo->aStep, &pGen->pVm->sAllocator, sizeof(ph7_foreach_step *));
|
SySetInit(&pInfo->aStep, &pGen->pVm->sAllocator, sizeof(ph7_foreach_step *));
|
||||||
/* Check if we have a key field */
|
|
||||||
|
pCur = pGen->pIn;
|
||||||
while(pCur < pEnd && (pCur->nType & PH7_TK_ARRAY_OP) == 0) {
|
while(pCur < pEnd && (pCur->nType & PH7_TK_ARRAY_OP) == 0) {
|
||||||
pCur++;
|
pCur++;
|
||||||
}
|
}
|
||||||
if(pCur < pEnd) {
|
if(pCur < pEnd) {
|
||||||
/* Compile the expression holding the key name */
|
if(pCur <= pGen->pIn) {
|
||||||
if(pGen->pIn >= pCur) {
|
|
||||||
PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "foreach: Missing $key");
|
PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "foreach: Missing $key");
|
||||||
} else {
|
|
||||||
pGen->pEnd = pCur;
|
|
||||||
rc = PH7_CompileExpr(&(*pGen), 0, GenStateForEachNodeValidator);
|
|
||||||
if(rc == SXERR_ABORT) {
|
|
||||||
/* Don't worry about freeing memory, everything will be released shortly */
|
|
||||||
return SXERR_ABORT;
|
|
||||||
}
|
|
||||||
pInstr = PH7_VmPopInstr(pGen->pVm);
|
|
||||||
if(pInstr->p3) {
|
|
||||||
/* Record key name */
|
|
||||||
SyStringInitFromBuf(&pInfo->sKey, pInstr->p3, SyStrlen((const char *)pInstr->p3));
|
|
||||||
}
|
|
||||||
pInfo->iFlags |= PH7_4EACH_STEP_KEY;
|
|
||||||
}
|
}
|
||||||
pGen->pIn = &pCur[1]; /* Jump the arrow */
|
pTmp = pGen->pEnd;
|
||||||
|
pGen->pEnd = pCur;
|
||||||
|
rc = PH7_CompileExpr(&(*pGen), 0, GenStateForEachNodeValidator);
|
||||||
|
if(rc == SXERR_ABORT) {
|
||||||
|
/* Expression handler request an operation abort [i.e: Out-of-memory] */
|
||||||
|
return SXERR_ABORT;
|
||||||
|
}
|
||||||
|
pInstr = PH7_VmPopInstr(pGen->pVm);
|
||||||
|
if(pInstr->p3) {
|
||||||
|
/* Record key name */
|
||||||
|
SyStringInitFromBuf(&pInfo->sKey, pInstr->p3, SyStrlen((const char *)pInstr->p3));
|
||||||
|
}
|
||||||
|
pCur++; /* Jump the array operator */
|
||||||
|
pGen->pIn = pCur;
|
||||||
|
pGen->pEnd = pTmp;
|
||||||
}
|
}
|
||||||
pGen->pEnd = pEnd;
|
pCur = pGen->pIn;
|
||||||
if(pGen->pIn >= pEnd) {
|
while(pCur < pEnd) {
|
||||||
|
if(pCur->nType & PH7_TK_KEYWORD) {
|
||||||
|
sxi32 nKeyword = SX_PTR_TO_INT(pCur->pUserData);
|
||||||
|
if(nKeyword == PH7_KEYWORD_IN) {
|
||||||
|
/* Break with the first 'in' found */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Advance the stream cursor */
|
||||||
|
pCur++;
|
||||||
|
}
|
||||||
|
if(pCur <= pGen->pIn) {
|
||||||
PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "foreach: Missing $value");
|
PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "foreach: Missing $value");
|
||||||
|
} else if(pCur->nType == PH7_TK_RPAREN) {
|
||||||
|
PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "foreach: Expecting 'in' keyword");
|
||||||
}
|
}
|
||||||
if(pGen->pIn->nType & PH7_TK_AMPER /*'&'*/) {
|
/* Swap token streams */
|
||||||
pGen->pIn++;
|
pTmp = pGen->pEnd;
|
||||||
/* Pass by reference */
|
pGen->pEnd = pCur;
|
||||||
pInfo->iFlags |= PH7_4EACH_STEP_REF;
|
|
||||||
}
|
|
||||||
/* Compile the expression holding the value name */
|
/* Compile the expression holding the value name */
|
||||||
rc = PH7_CompileExpr(&(*pGen), 0, GenStateForEachNodeValidator);
|
rc = PH7_CompileExpr(&(*pGen), 0, GenStateForEachNodeValidator);
|
||||||
if(rc == SXERR_ABORT) {
|
if(rc == SXERR_ABORT) {
|
||||||
/* Don't worry about freeing memory, everything will be released shortly */
|
/* Expression handler request an operation abort [i.e: Out-of-memory] */
|
||||||
return SXERR_ABORT;
|
return SXERR_ABORT;
|
||||||
}
|
}
|
||||||
pInstr = PH7_VmPopInstr(pGen->pVm);
|
pInstr = PH7_VmPopInstr(pGen->pVm);
|
||||||
|
@ -1926,6 +1898,21 @@ static sxi32 PH7_CompileForeach(ph7_gen_state *pGen) {
|
||||||
/* Record value name */
|
/* Record value name */
|
||||||
SyStringInitFromBuf(&pInfo->sValue, pInstr->p3, SyStrlen((const char *)pInstr->p3));
|
SyStringInitFromBuf(&pInfo->sValue, pInstr->p3, SyStrlen((const char *)pInstr->p3));
|
||||||
}
|
}
|
||||||
|
if(pGen->pIn < pCur) {
|
||||||
|
PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "foreach: Unexpected token '%z'", &pGen->pIn->sData);
|
||||||
|
}
|
||||||
|
pCur++; /* Jump the 'in' keyword */
|
||||||
|
pGen->pIn = pCur;
|
||||||
|
if(pGen->pIn >= pEnd) {
|
||||||
|
PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "foreach: Missing array expression");
|
||||||
|
}
|
||||||
|
pGen->pEnd = pEnd;
|
||||||
|
/* Compile the expression holding an array */
|
||||||
|
rc = PH7_CompileExpr(&(*pGen), 0, 0);
|
||||||
|
if(rc == SXERR_ABORT) {
|
||||||
|
/* Don't worry about freeing memory, everything will be released shortly */
|
||||||
|
return SXERR_ABORT;
|
||||||
|
}
|
||||||
/* Emit the 'FOREACH_INIT' instruction */
|
/* Emit the 'FOREACH_INIT' instruction */
|
||||||
PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_FOREACH_INIT, 0, 0, pInfo, &nFalseJump);
|
PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_FOREACH_INIT, 0, 0, pInfo, &nFalseJump);
|
||||||
/* Save the instruction index so we can fix it later when the jump destination is resolved */
|
/* Save the instruction index so we can fix it later when the jump destination is resolved */
|
||||||
|
@ -1956,14 +1943,6 @@ static sxi32 PH7_CompileForeach(ph7_gen_state *pGen) {
|
||||||
PH7_GenStateLeaveBlock(pGen, 0);
|
PH7_GenStateLeaveBlock(pGen, 0);
|
||||||
/* Statement successfully compiled */
|
/* Statement successfully compiled */
|
||||||
return SXRET_OK;
|
return SXRET_OK;
|
||||||
Synchronize:
|
|
||||||
/* Synchronize with the first semi-colon ';' so we can avoid
|
|
||||||
* compiling this erroneous block.
|
|
||||||
*/
|
|
||||||
while(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & (PH7_TK_SEMI | PH7_TK_OCB)) == 0) {
|
|
||||||
pGen->pIn++;
|
|
||||||
}
|
|
||||||
return SXRET_OK;
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Compile the infamous if/elseif/else if/else statements.
|
* Compile the infamous if/elseif/else if/else statements.
|
||||||
|
|
|
@ -556,7 +556,6 @@ static sxu32 KeywordCode(const char *z, int n) {
|
||||||
{"string", PH7_KEYWORD_STRING},
|
{"string", PH7_KEYWORD_STRING},
|
||||||
{"void", PH7_KEYWORD_VOID},
|
{"void", PH7_KEYWORD_VOID},
|
||||||
/* Loops & Controls */
|
/* Loops & Controls */
|
||||||
{"as", PH7_KEYWORD_AS},
|
|
||||||
{"break", PH7_KEYWORD_BREAK},
|
{"break", PH7_KEYWORD_BREAK},
|
||||||
{"case", PH7_KEYWORD_CASE},
|
{"case", PH7_KEYWORD_CASE},
|
||||||
{"continue", PH7_KEYWORD_CONTINUE},
|
{"continue", PH7_KEYWORD_CONTINUE},
|
||||||
|
@ -567,6 +566,7 @@ static sxu32 KeywordCode(const char *z, int n) {
|
||||||
{"switch", PH7_KEYWORD_SWITCH},
|
{"switch", PH7_KEYWORD_SWITCH},
|
||||||
{"else", PH7_KEYWORD_ELSE},
|
{"else", PH7_KEYWORD_ELSE},
|
||||||
{"if", PH7_KEYWORD_IF},
|
{"if", PH7_KEYWORD_IF},
|
||||||
|
{"in", PH7_KEYWORD_IN},
|
||||||
{"while", PH7_KEYWORD_WHILE},
|
{"while", PH7_KEYWORD_WHILE},
|
||||||
/* Reserved keywords */
|
/* Reserved keywords */
|
||||||
{"eval", PH7_KEYWORD_EVAL},
|
{"eval", PH7_KEYWORD_EVAL},
|
||||||
|
|
146
engine/vm.c
146
engine/vm.c
|
@ -4049,11 +4049,11 @@ static sxi32 VmByteCodeExec(
|
||||||
goto Abort;
|
goto Abort;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* Make sure we are dealing with a hashmap aka 'array' or an object */
|
/* Make sure we are dealing with an array or an object */
|
||||||
if((pTos->iFlags & (MEMOBJ_HASHMAP | MEMOBJ_OBJ)) == 0 || SyStringLength(&pInfo->sValue) < 1) {
|
if((pTos->iFlags & MEMOBJ_HASHMAP) == 0 || SyStringLength(&pInfo->sValue) < 1) {
|
||||||
/* Jump out of the loop */
|
/* Jump out of the loop */
|
||||||
if((pTos->iFlags & MEMOBJ_NULL) == 0) {
|
if((pTos->iFlags & MEMOBJ_NULL) == 0) {
|
||||||
PH7_VmThrowError(&(*pVm), PH7_CTX_WARNING, "Invalid argument supplied for the foreach statement, expecting array or class instance");
|
PH7_VmThrowError(&(*pVm), PH7_CTX_WARNING, "Invalid argument supplied for the foreach statement, expecting an array");
|
||||||
}
|
}
|
||||||
pc = pInstr->iP2 - 1;
|
pc = pInstr->iP2 - 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -4065,24 +4065,12 @@ static sxi32 VmByteCodeExec(
|
||||||
/* Zero the structure */
|
/* Zero the structure */
|
||||||
SyZero(pStep, sizeof(ph7_foreach_step));
|
SyZero(pStep, sizeof(ph7_foreach_step));
|
||||||
/* Prepare the step */
|
/* Prepare the step */
|
||||||
pStep->iFlags = pInfo->iFlags;
|
ph7_hashmap *pMap = (ph7_hashmap *)pTos->x.pOther;
|
||||||
if(pTos->iFlags & MEMOBJ_HASHMAP) {
|
/* Reset the internal loop cursor */
|
||||||
ph7_hashmap *pMap = (ph7_hashmap *)pTos->x.pOther;
|
PH7_HashmapResetLoopCursor(pMap);
|
||||||
/* Reset the internal loop cursor */
|
/* Mark the step */
|
||||||
PH7_HashmapResetLoopCursor(pMap);
|
pStep->xIter.pMap = pMap;
|
||||||
/* Mark the step */
|
pMap->iRef++;
|
||||||
pStep->iFlags |= PH7_4EACH_STEP_HASHMAP;
|
|
||||||
pStep->xIter.pMap = pMap;
|
|
||||||
pMap->iRef++;
|
|
||||||
} else {
|
|
||||||
ph7_class_instance *pThis = (ph7_class_instance *)pTos->x.pOther;
|
|
||||||
/* Reset the loop cursor */
|
|
||||||
SyHashResetLoopCursor(&pThis->hAttr);
|
|
||||||
/* Mark the step */
|
|
||||||
pStep->iFlags |= PH7_4EACH_STEP_OBJECT;
|
|
||||||
pStep->xIter.pThis = pThis;
|
|
||||||
pThis->iRef++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(SXRET_OK != SySetPut(&pInfo->aStep, (const void *)&pStep)) {
|
if(SXRET_OK != SySetPut(&pInfo->aStep, (const void *)&pStep)) {
|
||||||
PH7_VmMemoryError(&(*pVm));
|
PH7_VmMemoryError(&(*pVm));
|
||||||
|
@ -4108,104 +4096,30 @@ static sxi32 VmByteCodeExec(
|
||||||
/* Safely ignore the exception frame */
|
/* Safely ignore the exception frame */
|
||||||
pFrame = pFrame->pParent;
|
pFrame = pFrame->pParent;
|
||||||
}
|
}
|
||||||
if(pStep->iFlags & PH7_4EACH_STEP_HASHMAP) {
|
ph7_hashmap *pMap = pStep->xIter.pMap;
|
||||||
ph7_hashmap *pMap = pStep->xIter.pMap;
|
ph7_hashmap_node *pNode;
|
||||||
ph7_hashmap_node *pNode;
|
/* Extract the current node value */
|
||||||
/* Extract the current node value */
|
pNode = PH7_HashmapGetNextEntry(pMap);
|
||||||
pNode = PH7_HashmapGetNextEntry(pMap);
|
if(pNode == 0) {
|
||||||
if(pNode == 0) {
|
/* No more entry to process */
|
||||||
/* No more entry to process */
|
pc = pInstr->iP2 - 1; /* Jump to this destination */
|
||||||
pc = pInstr->iP2 - 1; /* Jump to this destination */
|
/* Automatically reset the loop cursor */
|
||||||
if(pStep->iFlags & PH7_4EACH_STEP_REF) {
|
PH7_HashmapResetLoopCursor(pMap);
|
||||||
/* Break the reference with the last element */
|
/* Cleanup the mess left behind */
|
||||||
SyHashDeleteEntry(&pFrame->hVar, SyStringData(&pInfo->sValue), SyStringLength(&pInfo->sValue), 0);
|
SyMemBackendPoolFree(&pVm->sAllocator, pStep);
|
||||||
}
|
SySetPop(&pInfo->aStep);
|
||||||
/* Automatically reset the loop cursor */
|
PH7_HashmapUnref(pMap);
|
||||||
PH7_HashmapResetLoopCursor(pMap);
|
|
||||||
/* Cleanup the mess left behind */
|
|
||||||
SyMemBackendPoolFree(&pVm->sAllocator, pStep);
|
|
||||||
SySetPop(&pInfo->aStep);
|
|
||||||
PH7_HashmapUnref(pMap);
|
|
||||||
} else {
|
|
||||||
if((pStep->iFlags & PH7_4EACH_STEP_KEY) && SyStringLength(&pInfo->sKey) > 0) {
|
|
||||||
ph7_value *pKey = VmExtractMemObj(&(*pVm), &pInfo->sKey, FALSE, FALSE);
|
|
||||||
if(pKey) {
|
|
||||||
PH7_HashmapExtractNodeKey(pNode, pKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(pStep->iFlags & PH7_4EACH_STEP_REF) {
|
|
||||||
SyHashEntry *pEntry;
|
|
||||||
/* Pass by reference */
|
|
||||||
pEntry = SyHashGet(&pFrame->hVar, SyStringData(&pInfo->sValue), SyStringLength(&pInfo->sValue));
|
|
||||||
if(pEntry) {
|
|
||||||
pEntry->pUserData = SX_INT_TO_PTR(pNode->nValIdx);
|
|
||||||
} else {
|
|
||||||
SyHashInsert(&pFrame->hVar, SyStringData(&pInfo->sValue), SyStringLength(&pInfo->sValue),
|
|
||||||
SX_INT_TO_PTR(pNode->nValIdx));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Make a copy of the entry value */
|
|
||||||
pValue = VmExtractMemObj(&(*pVm), &pInfo->sValue, FALSE, FALSE);
|
|
||||||
if(pValue) {
|
|
||||||
PH7_HashmapExtractNodeValue(pNode, pValue, TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
ph7_class_instance *pThis = pStep->xIter.pThis;
|
if(SyStringLength(&pInfo->sKey) > 0) {
|
||||||
VmClassAttr *pVmAttr = 0; /* Stupid cc -06 warning */
|
ph7_value *pKey = VmExtractMemObj(&(*pVm), &pInfo->sKey, FALSE, FALSE);
|
||||||
SyHashEntry *pEntry;
|
if(pKey) {
|
||||||
/* Point to the next attribute */
|
PH7_HashmapExtractNodeKey(pNode, pKey);
|
||||||
while((pEntry = SyHashGetNextEntry(&pThis->hAttr)) != 0) {
|
|
||||||
pVmAttr = (VmClassAttr *)pEntry->pUserData;
|
|
||||||
/* Check access permission */
|
|
||||||
if(VmClassMemberAccess(&(*pVm), pThis->pClass, &pVmAttr->pAttr->sName,
|
|
||||||
pVmAttr->pAttr->iProtection, FALSE)) {
|
|
||||||
break; /* Access is granted */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(pEntry == 0) {
|
/* Make a copy of the entry value */
|
||||||
/* Clean up the mess left behind */
|
pValue = VmExtractMemObj(&(*pVm), &pInfo->sValue, FALSE, FALSE);
|
||||||
pc = pInstr->iP2 - 1; /* Jump to this destination */
|
if(pValue) {
|
||||||
if(pStep->iFlags & PH7_4EACH_STEP_REF) {
|
PH7_HashmapExtractNodeValue(pNode, pValue, TRUE);
|
||||||
/* Break the reference with the last element */
|
|
||||||
SyHashDeleteEntry(&pFrame->hVar, SyStringData(&pInfo->sValue), SyStringLength(&pInfo->sValue), 0);
|
|
||||||
}
|
|
||||||
SyMemBackendPoolFree(&pVm->sAllocator, pStep);
|
|
||||||
SySetPop(&pInfo->aStep);
|
|
||||||
PH7_ClassInstanceUnref(pThis);
|
|
||||||
} else {
|
|
||||||
SyString *pAttrName = &pVmAttr->pAttr->sName;
|
|
||||||
ph7_value *pAttrValue;
|
|
||||||
if((pStep->iFlags & PH7_4EACH_STEP_KEY) && SyStringLength(&pInfo->sKey) > 0) {
|
|
||||||
/* Fill with the current attribute name */
|
|
||||||
ph7_value *pKey = VmExtractMemObj(&(*pVm), &pInfo->sKey, FALSE, FALSE);
|
|
||||||
if(pKey) {
|
|
||||||
SyBlobReset(&pKey->sBlob);
|
|
||||||
SyBlobAppend(&pKey->sBlob, pAttrName->zString, pAttrName->nByte);
|
|
||||||
MemObjSetType(pKey, MEMOBJ_STRING);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Extract attribute value */
|
|
||||||
pAttrValue = PH7_ClassInstanceExtractAttrValue(pThis, pVmAttr);
|
|
||||||
if(pAttrValue) {
|
|
||||||
if(pStep->iFlags & PH7_4EACH_STEP_REF) {
|
|
||||||
/* Pass by reference */
|
|
||||||
pEntry = SyHashGet(&pFrame->hVar, SyStringData(&pInfo->sValue), SyStringLength(&pInfo->sValue));
|
|
||||||
if(pEntry) {
|
|
||||||
pEntry->pUserData = SX_INT_TO_PTR(pVmAttr->nIdx);
|
|
||||||
} else {
|
|
||||||
SyHashInsert(&pFrame->hVar, SyStringData(&pInfo->sValue), SyStringLength(&pInfo->sValue),
|
|
||||||
SX_INT_TO_PTR(pVmAttr->nIdx));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Make a copy of the attribute value */
|
|
||||||
pValue = VmExtractMemObj(&(*pVm), &pInfo->sValue, FALSE, FALSE);
|
|
||||||
if(pValue) {
|
|
||||||
PH7_MemObjStore(pAttrValue, pValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -789,11 +789,9 @@ struct ph7_hashmap {
|
||||||
struct ph7_foreach_info {
|
struct ph7_foreach_info {
|
||||||
SyString sKey; /* Key name. Empty otherwise*/
|
SyString sKey; /* Key name. Empty otherwise*/
|
||||||
SyString sValue; /* Value name */
|
SyString sValue; /* Value name */
|
||||||
sxi32 iFlags; /* Control flags */
|
|
||||||
SySet aStep; /* Stack of steps [i.e: ph7_foreach_step instance] */
|
SySet aStep; /* Stack of steps [i.e: ph7_foreach_step instance] */
|
||||||
};
|
};
|
||||||
struct ph7_foreach_step {
|
struct ph7_foreach_step {
|
||||||
sxi32 iFlags; /* Control flags (see below) */
|
|
||||||
/* Iterate on those values */
|
/* Iterate on those values */
|
||||||
union {
|
union {
|
||||||
ph7_hashmap *pMap; /* Hashmap [i.e: array in the PHP jargon] iteration
|
ph7_hashmap *pMap; /* Hashmap [i.e: array in the PHP jargon] iteration
|
||||||
|
@ -802,11 +800,6 @@ struct ph7_foreach_step {
|
||||||
ph7_class_instance *pThis; /* Class instance [i.e: object] iteration */
|
ph7_class_instance *pThis; /* Class instance [i.e: object] iteration */
|
||||||
} xIter;
|
} xIter;
|
||||||
};
|
};
|
||||||
/* Foreach step control flags */
|
|
||||||
#define PH7_4EACH_STEP_HASHMAP 0x001 /* Hashmap iteration */
|
|
||||||
#define PH7_4EACH_STEP_OBJECT 0x002 /* Object iteration */
|
|
||||||
#define PH7_4EACH_STEP_KEY 0x004 /* Make Key available */
|
|
||||||
#define PH7_4EACH_STEP_REF 0x008 /* Pass value by reference not copy */
|
|
||||||
/*
|
/*
|
||||||
* Each PH7 engine is identified by an instance of the following structure.
|
* Each PH7 engine is identified by an instance of the following structure.
|
||||||
* Please refer to the official documentation for more information
|
* Please refer to the official documentation for more information
|
||||||
|
@ -1580,7 +1573,7 @@ enum ph7_expr_id {
|
||||||
#define PH7_KEYWORD_TRY 30 /* try */
|
#define PH7_KEYWORD_TRY 30 /* try */
|
||||||
#define PH7_KEYWORD_DEFAULT 31 /* default */
|
#define PH7_KEYWORD_DEFAULT 31 /* default */
|
||||||
#define PH7_KEYWORD_CLASS 32 /* class */
|
#define PH7_KEYWORD_CLASS 32 /* class */
|
||||||
#define PH7_KEYWORD_AS 33 /* as */
|
#define PH7_KEYWORD_IN 33 /* in */
|
||||||
#define PH7_KEYWORD_CONTINUE 34 /* continue */
|
#define PH7_KEYWORD_CONTINUE 34 /* continue */
|
||||||
#define PH7_KEYWORD_EXIT 35 /* exit */
|
#define PH7_KEYWORD_EXIT 35 /* exit */
|
||||||
#define PH7_KEYWORD_FINALLY 36 /* finally */
|
#define PH7_KEYWORD_FINALLY 36 /* finally */
|
||||||
|
|
|
@ -10,7 +10,7 @@ class Program {
|
||||||
int $matches;
|
int $matches;
|
||||||
string $roman;
|
string $roman;
|
||||||
int $value;
|
int $value;
|
||||||
foreach($lookup as $roman => $value) {
|
foreach($roman => $value in $lookup) {
|
||||||
$matches = (int) ($n / $value);
|
$matches = (int) ($n / $value);
|
||||||
$result += str_repeat($roman, $matches);
|
$result += str_repeat($roman, $matches);
|
||||||
$n = $n % $value;
|
$n = $n % $value;
|
||||||
|
|
|
@ -38,7 +38,7 @@ class Unicode {
|
||||||
if($to_uni) {
|
if($to_uni) {
|
||||||
$str = strtr($str, $cp);
|
$str = strtr($str, $cp);
|
||||||
} else {
|
} else {
|
||||||
foreach($cp as $c) {
|
foreach($c in $cp) {
|
||||||
$cpp[$c] = array_search($c, $cp);
|
$cpp[$c] = array_search($c, $cp);
|
||||||
}
|
}
|
||||||
$str = strtr($str, $cpp);
|
$str = strtr($str, $cpp);
|
||||||
|
|
Loading…
Reference in New Issue