Typehinting merge #50
@ -2490,118 +2490,6 @@ static sxi32 PH7_CompileHalt(ph7_gen_state *pGen) {
|
||||
PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_HALT, nExpr, 0, 0, 0);
|
||||
return SXRET_OK;
|
||||
}
|
||||
/*
|
||||
* Compile the static statement.
|
||||
* Another important feature of variable scoping is the static variable.
|
||||
* A static variable exists only in a local function scope, but it does not lose its value
|
||||
* when program execution leaves this scope.
|
||||
* Static variables also provide one way to deal with recursive functions.
|
||||
* Symisc eXtension.
|
||||
* PH7 allow any complex expression to be associated with the static variable while
|
||||
* the zend engine would allow only simple scalar value.
|
||||
* Example
|
||||
* static $myVar = "Welcome "." guest ".rand_str(3); //Valid under PH7/Generate error using the zend engine
|
||||
* Refer to the official documentation for more information on this feature.
|
||||
*/
|
||||
static sxi32 PH7_CompileStatic(ph7_gen_state *pGen) {
|
||||
ph7_vm_func_static_var sStatic; /* Structure describing the static variable */
|
||||
ph7_vm_func *pFunc; /* Enclosing function */
|
||||
GenBlock *pBlock;
|
||||
SyString *pName;
|
||||
char *zDup;
|
||||
sxu32 nLine;
|
||||
sxi32 rc;
|
||||
/* Jump the static keyword */
|
||||
nLine = pGen->pIn->nLine;
|
||||
pGen->pIn++;
|
||||
/* Extract the enclosing function if any */
|
||||
pBlock = pGen->pCurrent;
|
||||
while(pBlock) {
|
||||
if(pBlock->iFlags & GEN_BLOCK_FUNC) {
|
||||
break;
|
||||
}
|
||||
/* Point to the upper block */
|
||||
pBlock = pBlock->pParent;
|
||||
}
|
||||
if(pBlock == 0) {
|
||||
/* Static statement,called outside of a function body,treat it as a simple variable. */
|
||||
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_DOLLAR) == 0) {
|
||||
rc = PH7_GenCompileError(&(*pGen), E_ERROR, nLine, "Expected variable after 'static' keyword");
|
||||
if(rc == SXERR_ABORT) {
|
||||
return SXERR_ABORT;
|
||||
}
|
||||
goto Synchronize;
|
||||
}
|
||||
/* Compile the expression holding the variable */
|
||||
rc = PH7_CompileExpr(&(*pGen), 0, 0);
|
||||
if(rc == SXERR_ABORT) {
|
||||
return SXERR_ABORT;
|
||||
} else if(rc != SXERR_EMPTY) {
|
||||
/* Emit the POP instruction */
|
||||
PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_POP, 1, 0, 0, 0);
|
||||
}
|
||||
return SXRET_OK;
|
||||
}
|
||||
pFunc = (ph7_vm_func *)pBlock->pUserData;
|
||||
/* Make sure we are dealing with a valid statement */
|
||||
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_DOLLAR) == 0 || &pGen->pIn[1] >= pGen->pEnd ||
|
||||
(pGen->pIn[1].nType & (PH7_TK_ID | PH7_TK_KEYWORD)) == 0) {
|
||||
rc = PH7_GenCompileError(&(*pGen), E_ERROR, nLine, "Expected variable after 'static' keyword");
|
||||
if(rc == SXERR_ABORT) {
|
||||
return SXERR_ABORT;
|
||||
}
|
||||
goto Synchronize;
|
||||
}
|
||||
pGen->pIn++;
|
||||
/* Extract variable name */
|
||||
pName = &pGen->pIn->sData;
|
||||
pGen->pIn++; /* Jump the var name */
|
||||
if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & (PH7_TK_SEMI/*';'*/ | PH7_TK_EQUAL/*'='*/)) == 0) {
|
||||
rc = PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "static: Unexpected token '%z'", &pGen->pIn->sData);
|
||||
goto Synchronize;
|
||||
}
|
||||
/* Initialize the structure describing the static variable */
|
||||
SySetInit(&sStatic.aByteCode, &pGen->pVm->sAllocator, sizeof(VmInstr));
|
||||
sStatic.nIdx = SXU32_HIGH; /* Not yet created */
|
||||
/* Duplicate variable name */
|
||||
zDup = SyMemBackendStrDup(&pGen->pVm->sAllocator, pName->zString, pName->nByte);
|
||||
if(zDup == 0) {
|
||||
PH7_GenCompileError(&(*pGen), E_ERROR, nLine, "Fatal, PH7 engine is running out of memory");
|
||||
return SXERR_ABORT;
|
||||
}
|
||||
SyStringInitFromBuf(&sStatic.sName, zDup, pName->nByte);
|
||||
/* Check if we have an expression to compile */
|
||||
if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_EQUAL)) {
|
||||
SySet *pInstrContainer;
|
||||
/*
|
||||
* Static variable can take any complex expression including function
|
||||
* call as their initialization value.
|
||||
* Example:
|
||||
* static $var = foo(1,4+5,bar());
|
||||
*/
|
||||
pGen->pIn++; /* Jump the equal '=' sign */
|
||||
/* Swap bytecode container */
|
||||
pInstrContainer = PH7_VmGetByteCodeContainer(pGen->pVm);
|
||||
PH7_VmSetByteCodeContainer(pGen->pVm, &sStatic.aByteCode);
|
||||
/* Compile the expression */
|
||||
rc = PH7_CompileExpr(&(*pGen), 0, 0);
|
||||
/* Emit the done instruction */
|
||||
PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_DONE, (rc != SXERR_EMPTY ? 1 : 0), 0, 0, 0);
|
||||
/* Restore default bytecode container */
|
||||
PH7_VmSetByteCodeContainer(pGen->pVm, pInstrContainer);
|
||||
}
|
||||
/* Finally save the compiled static variable in the appropriate container */
|
||||
SySetPut(&pFunc->aStatic, (const void *)&sStatic);
|
||||
return SXRET_OK;
|
||||
Synchronize:
|
||||
/* Synchronize with the first semi-colon ';',so we can avoid compiling this erroneous
|
||||
* statement.
|
||||
*/
|
||||
while(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_SEMI) == 0) {
|
||||
pGen->pIn++;
|
||||
}
|
||||
return SXRET_OK;
|
||||
}
|
||||
/*
|
||||
* Compile the var statement.
|
||||
* Symisc Extension:
|
||||
|
Loading…
Reference in New Issue
Block a user