Make constant declarations local.
The build was successful.
Details
The build was successful.
Details
There are several changes in this commit: * first of all constants declared by 'const' statement should be local (declared in current scope / frame), * constants are declared by using OP_DECLARE instruction, * OP_LOADC browses both global and local constants container, * PH7_VmRegisterConstant() allows both global and local declarations. Since this commit, there are 3 kinds of constants: 1) global 2) local (in loop, closure, method) 3) class members. Actually there is no way to declare a global constant except the built-in constants.
This commit is contained in:
parent
90b2da7c56
commit
ab8bf48485
|
@ -1064,7 +1064,7 @@ int ph7_create_constant(ph7_vm *pVm, const char *zName, void (*xExpand)(ph7_valu
|
|||
}
|
||||
#endif
|
||||
/* Perform the registration */
|
||||
rc = PH7_VmRegisterConstant(&(*pVm), &sName, xExpand, pUserData);
|
||||
rc = PH7_VmRegisterConstant(&(*pVm), &sName, xExpand, pUserData, TRUE);
|
||||
#if defined(PH7_ENABLE_THREADS)
|
||||
/* Leave VM mutex */
|
||||
SyMutexLeave(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
|
||||
|
|
|
@ -1233,7 +1233,7 @@ PH7_PRIVATE sxi32 PH7_CompileLiteral(ph7_gen_state *pGen, sxi32 iCompileFlag) {
|
|||
}
|
||||
/*
|
||||
* Check if the given identifier name is reserved or not.
|
||||
* Return TRUE if reserved.FALSE otherwise.
|
||||
* Return TRUE if reserved. FALSE otherwise.
|
||||
*/
|
||||
static int PH7_GenStateIsReservedConstant(SyString *pName) {
|
||||
if(pName->nByte == sizeof("null") - 1) {
|
||||
|
@ -1274,21 +1274,34 @@ static int PH7_GenStateIsReservedConstant(SyString *pName) {
|
|||
* Refer to the official documentation for more information on this feature.
|
||||
*/
|
||||
static sxi32 PH7_CompileConstant(ph7_gen_state *pGen) {
|
||||
SySet *pConsCode, *pInstrContainer;
|
||||
SySet *pInstrContainer;
|
||||
ph7_constant_info *pConstInfo;
|
||||
sxu32 nLine = pGen->pIn->nLine;
|
||||
SyString *pName;
|
||||
char *zName;
|
||||
sxi32 rc;
|
||||
pGen->pIn++; /* Jump the 'const' keyword */
|
||||
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & (PH7_TK_SSTR | PH7_TK_DSTR | PH7_TK_ID | PH7_TK_KEYWORD)) == 0) {
|
||||
/* Invalid constant name */
|
||||
PH7_GenCompileError(pGen, E_ERROR, nLine, "const: Invalid constant name");
|
||||
}
|
||||
/* Allocate a new instance */
|
||||
pConstInfo = (ph7_constant_info *)SyMemBackendPoolAlloc(&pGen->pVm->sAllocator, sizeof(ph7_constant_info));
|
||||
if(pConstInfo == 0) {
|
||||
PH7_GenCompileError(pGen, E_ERROR, nLine, "PH7 engine is running out-of-memory");
|
||||
}
|
||||
/* Zero the structure */
|
||||
SyZero(pConstInfo, sizeof(ph7_constant_info));
|
||||
/* Peek constant name */
|
||||
pName = &pGen->pIn->sData;
|
||||
zName = SyMemBackendStrDup(&pGen->pVm->sAllocator, pGen->pIn->sData.zString, pGen->pIn->sData.nByte);
|
||||
if(zName == 0) {
|
||||
PH7_GenCompileError(pGen, E_ERROR, nLine, "PH7 engine is running out-of-memory");
|
||||
}
|
||||
/* Duplicate constant name */
|
||||
SyStringInitFromBuf(&pConstInfo->pName, zName, pGen->pIn->sData.nByte);
|
||||
/* Make sure the constant name isn't reserved */
|
||||
if(PH7_GenStateIsReservedConstant(pName)) {
|
||||
if(PH7_GenStateIsReservedConstant(&pConstInfo->pName)) {
|
||||
/* Reserved constant */
|
||||
PH7_GenCompileError(pGen, E_ERROR, nLine, "const: Cannot redeclare a reserved constant '%z'", pName);
|
||||
PH7_GenCompileError(pGen, E_ERROR, nLine, "const: Cannot redeclare a reserved constant '%z'", pConstInfo->pName);
|
||||
}
|
||||
pGen->pIn++;
|
||||
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_EQUAL /* '=' */) == 0) {
|
||||
|
@ -1297,14 +1310,14 @@ static sxi32 PH7_CompileConstant(ph7_gen_state *pGen) {
|
|||
}
|
||||
pGen->pIn++; /*Jump the equal sign */
|
||||
/* Allocate a new constant value container */
|
||||
pConsCode = (SySet *)SyMemBackendPoolAlloc(&pGen->pVm->sAllocator, sizeof(SySet));
|
||||
if(pConsCode == 0) {
|
||||
pConstInfo->pConsCode = (SySet *)SyMemBackendPoolAlloc(&pGen->pVm->sAllocator, sizeof(SySet));
|
||||
if(pConstInfo->pConsCode == 0) {
|
||||
PH7_GenCompileError(pGen, E_ERROR, nLine, "PH7 engine is running out-of-memory");
|
||||
}
|
||||
SySetInit(pConsCode, &pGen->pVm->sAllocator, sizeof(VmInstr));
|
||||
SySetInit(pConstInfo->pConsCode, &pGen->pVm->sAllocator, sizeof(VmInstr));
|
||||
/* Swap bytecode container */
|
||||
pInstrContainer = PH7_VmGetByteCodeContainer(pGen->pVm);
|
||||
PH7_VmSetByteCodeContainer(pGen->pVm, pConsCode);
|
||||
PH7_VmSetByteCodeContainer(pGen->pVm, pConstInfo->pConsCode);
|
||||
/* Compile constant value */
|
||||
rc = PH7_CompileExpr(&(*pGen), 0, 0);
|
||||
/* Emit the done instruction */
|
||||
|
@ -1314,19 +1327,9 @@ static sxi32 PH7_CompileConstant(ph7_gen_state *pGen) {
|
|||
/* Don't worry about freeing memory, everything will be released shortly */
|
||||
return SXERR_ABORT;
|
||||
}
|
||||
SySetSetUserData(pConsCode, pGen->pVm);
|
||||
/* Register the constant */
|
||||
rc = PH7_VmRegisterConstant(pGen->pVm, pName, PH7_VmExpandConstantValue, pConsCode);
|
||||
if(rc != SXRET_OK) {
|
||||
SySetRelease(pConsCode);
|
||||
SyMemBackendPoolFree(&pGen->pVm->sAllocator, pConsCode);
|
||||
}
|
||||
return SXRET_OK;
|
||||
Synchronize:
|
||||
/* Synchronize with the next-semi-colon and avoid compiling this erroneous statement */
|
||||
while(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_SEMI) == 0) {
|
||||
pGen->pIn++;
|
||||
}
|
||||
SySetSetUserData(pConstInfo->pConsCode, pGen->pVm);
|
||||
/* Declare the constant in active frame */
|
||||
PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_DECLARE, 1, 0, pConstInfo, 0);
|
||||
return SXRET_OK;
|
||||
}
|
||||
/*
|
||||
|
|
115
engine/vm.c
115
engine/vm.c
|
@ -69,40 +69,41 @@ PH7_PRIVATE sxi32 PH7_VmRegisterConstant(
|
|||
ph7_vm *pVm, /* Target VM */
|
||||
const SyString *pName, /* Constant name */
|
||||
ProcConstant xExpand, /* Constant expansion callback */
|
||||
void *pUserData /* Last argument to xExpand() */
|
||||
void *pUserData, /* Last argument to xExpand() */
|
||||
sxbool bGlobal /* Whether this is a global constant or not */
|
||||
) {
|
||||
ph7_constant *pCons;
|
||||
SyHash *pCollection;
|
||||
SyHashEntry *pEntry;
|
||||
char *zDupName;
|
||||
sxi32 rc;
|
||||
pEntry = SyHashGet(&pVm->hConstant, (const void *)pName->zString, pName->nByte);
|
||||
if(bGlobal) {
|
||||
pCollection = &pVm->hConstant;
|
||||
} else {
|
||||
pCollection = &pVm->pFrame->hConst;
|
||||
}
|
||||
pEntry = SyHashGet(pCollection, (const void *)pName->zString, pName->nByte);
|
||||
if(pEntry) {
|
||||
/* Overwrite the old definition and return immediately */
|
||||
pCons = (ph7_constant *)pEntry->pUserData;
|
||||
pCons->xExpand = xExpand;
|
||||
pCons->pUserData = pUserData;
|
||||
return SXRET_OK;
|
||||
/* Constant already exists */
|
||||
return SXERR_EXISTS;
|
||||
}
|
||||
/* Allocate a new constant instance */
|
||||
pCons = (ph7_constant *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(ph7_constant));
|
||||
if(pCons == 0) {
|
||||
return 0;
|
||||
PH7_VmMemoryError(&(*pVm));
|
||||
}
|
||||
/* Duplicate constant name */
|
||||
zDupName = SyMemBackendStrDup(&pVm->sAllocator, pName->zString, pName->nByte);
|
||||
if(zDupName == 0) {
|
||||
SyMemBackendPoolFree(&pVm->sAllocator, pCons);
|
||||
return 0;
|
||||
PH7_VmMemoryError(&(*pVm));
|
||||
}
|
||||
/* Install the constant */
|
||||
SyStringInitFromBuf(&pCons->sName, zDupName, pName->nByte);
|
||||
pCons->xExpand = xExpand;
|
||||
pCons->pUserData = pUserData;
|
||||
rc = SyHashInsert(&pVm->hConstant, (const void *)zDupName, SyStringLength(&pCons->sName), pCons);
|
||||
rc = SyHashInsert(pCollection, (const void *)zDupName, SyStringLength(&pCons->sName), pCons);
|
||||
if(rc != SXRET_OK) {
|
||||
SyMemBackendFree(&pVm->sAllocator, zDupName);
|
||||
SyMemBackendPoolFree(&pVm->sAllocator, pCons);
|
||||
return rc;
|
||||
PH7_VmMemoryError(&(*pVm));
|
||||
}
|
||||
/* All done,constant can be invoked from PHP code */
|
||||
return SXRET_OK;
|
||||
|
@ -385,6 +386,7 @@ static VmFrame *VmNewFrame(
|
|||
pFrame->pUserData = pUserData;
|
||||
pFrame->pThis = pThis;
|
||||
pFrame->pVm = pVm;
|
||||
SyHashInit(&pFrame->hConst, &pVm->sAllocator, 0, 0);
|
||||
SyHashInit(&pFrame->hVar, &pVm->sAllocator, 0, 0);
|
||||
SySetInit(&pFrame->sArg, &pVm->sAllocator, sizeof(VmSlot));
|
||||
SySetInit(&pFrame->sLocal, &pVm->sAllocator, sizeof(VmSlot));
|
||||
|
@ -439,6 +441,7 @@ static void VmLeaveFrame(ph7_vm *pVm) {
|
|||
}
|
||||
}
|
||||
/* Release internal containers */
|
||||
SyHashRelease(&pFrame->hConst);
|
||||
SyHashRelease(&pFrame->hVar);
|
||||
SySetRelease(&pFrame->sArg);
|
||||
SySetRelease(&pFrame->sLocal);
|
||||
|
@ -2372,39 +2375,51 @@ static sxi32 VmByteCodeExec(
|
|||
break;
|
||||
}
|
||||
/*
|
||||
* DECLARE: * P2 P3
|
||||
* DECLARE: P1 P2 P3
|
||||
*
|
||||
* Create a variable where it's name is taken from the top of the stack or
|
||||
* from the P3 operand. It takes a variable type from P2 operand.
|
||||
* Create a constant if P1 is set, or variable otherwise. It takes the constant/variable name
|
||||
* from the the P3 operand. P2 operand is used to provide a variable type.
|
||||
*/
|
||||
case PH7_OP_DECLARE: {
|
||||
ph7_value *pObj;
|
||||
SyString sName;
|
||||
SyStringInitFromBuf(&sName, pInstr->p3, SyStrlen((const char *)pInstr->p3));
|
||||
/* Reserve a room for the target object */
|
||||
pTos++;
|
||||
/* Create a new variable */
|
||||
pObj = VmCreateMemObj(&(*pVm), &sName, FALSE);
|
||||
if(!pObj) {
|
||||
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR,
|
||||
"Redeclaration of ‘$%z’ variable", &sName);
|
||||
}
|
||||
if(pInstr->iP2 & MEMOBJ_MIXED && (pInstr->iP2 & MEMOBJ_HASHMAP) == 0) {
|
||||
pObj->iFlags = MEMOBJ_MIXED | MEMOBJ_VOID;
|
||||
} else {
|
||||
if(pInstr->iP2 & MEMOBJ_HASHMAP) {
|
||||
ph7_hashmap *pMap;
|
||||
pMap = PH7_NewHashmap(&(*pVm), 0, 0);
|
||||
if(pMap == 0) {
|
||||
PH7_VmMemoryError(&(*pVm));
|
||||
}
|
||||
pObj->x.pOther = pMap;
|
||||
if(pInstr->iP1) {
|
||||
/* Constant declaration */
|
||||
ph7_constant_info *pConstInfo = (ph7_constant_info *) pInstr->p3;
|
||||
rc = PH7_VmRegisterConstant(&(*pVm), &pConstInfo->pName, PH7_VmExpandConstantValue, pConstInfo->pConsCode, FALSE);
|
||||
if(rc == SXERR_EXISTS) {
|
||||
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR,
|
||||
"Redeclaration of ‘%z’ constant", &pConstInfo->pName);
|
||||
}
|
||||
MemObjSetType(pObj, pInstr->iP2);
|
||||
} else {
|
||||
/* Variable declaration */
|
||||
ph7_value *pObj;
|
||||
SyString sName;
|
||||
SyStringInitFromBuf(&sName, pInstr->p3, SyStrlen((const char *)pInstr->p3));
|
||||
/* Reserve a room for the target object */
|
||||
pTos++;
|
||||
/* Create a new variable */
|
||||
pObj = VmCreateMemObj(&(*pVm), &sName, FALSE);
|
||||
if(!pObj) {
|
||||
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR,
|
||||
"Redeclaration of ‘$%z’ variable", &sName);
|
||||
}
|
||||
if(pInstr->iP2 & MEMOBJ_MIXED && (pInstr->iP2 & MEMOBJ_HASHMAP) == 0) {
|
||||
pObj->iFlags = MEMOBJ_MIXED | MEMOBJ_VOID;
|
||||
} else {
|
||||
if(pInstr->iP2 & MEMOBJ_HASHMAP) {
|
||||
ph7_hashmap *pMap;
|
||||
pMap = PH7_NewHashmap(&(*pVm), 0, 0);
|
||||
if(pMap == 0) {
|
||||
PH7_VmMemoryError(&(*pVm));
|
||||
}
|
||||
pObj->x.pOther = pMap;
|
||||
}
|
||||
MemObjSetType(pObj, pInstr->iP2);
|
||||
}
|
||||
pTos->nIdx = SXU32_HIGH; /* Mark as constant */
|
||||
}
|
||||
pTos->nIdx = SXU32_HIGH; /* Mark as constant */
|
||||
break;
|
||||
} /*
|
||||
}
|
||||
/*
|
||||
* LOADC P1 P2 *
|
||||
*
|
||||
* Load a constant [i.e: PHP_EOL,PHP_OS,__TIME__,...] indexed at P2 in the constant pool.
|
||||
|
@ -2416,9 +2431,25 @@ static sxi32 VmByteCodeExec(
|
|||
pTos++;
|
||||
if((pObj = (ph7_value *)SySetAt(&pVm->aLitObj, pInstr->iP2)) != 0) {
|
||||
if(pInstr->iP1 == 1 && SyBlobLength(&pObj->sBlob) <= 64) {
|
||||
/* Point to the top active frame */
|
||||
VmFrame *pFrame = pVm->pFrame;
|
||||
while(pFrame->pParent && (pFrame->iFlags & VM_FRAME_EXCEPTION)) {
|
||||
/* Safely ignore the exception frame */
|
||||
pFrame = pFrame->pParent; /* Parent frame */
|
||||
}
|
||||
SyHashEntry *pEntry;
|
||||
/* Candidate for expansion via user defined callbacks */
|
||||
pEntry = SyHashGet(&pVm->hConstant, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
|
||||
for(;;) {
|
||||
pEntry = SyHashGet(&pVm->pFrame->hConst, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
|
||||
if(pEntry == 0 && pFrame->iFlags & VM_FRAME_LOOP && pFrame->pParent) {
|
||||
pFrame = pFrame->pParent;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(pEntry == 0) {
|
||||
pEntry = SyHashGet(&pVm->hConstant, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
|
||||
}
|
||||
if(pEntry) {
|
||||
ph7_constant *pCons = (ph7_constant *)pEntry->pUserData;
|
||||
/* Set a NULL default value */
|
||||
|
|
|
@ -691,6 +691,15 @@ struct ph7_conf {
|
|||
* Signature of the C function responsible of expanding constant values.
|
||||
*/
|
||||
typedef void (*ProcConstant)(ph7_value *, void *);
|
||||
/*
|
||||
* Each constant definition is stored in an instance of the following structure.
|
||||
* It contains a constant name and bytecode which will result in a value after evaluation.
|
||||
*/
|
||||
typedef struct ph7_constant_info ph7_constant_info;
|
||||
struct ph7_constant_info {
|
||||
SyString pName;
|
||||
SySet *pConsCode;
|
||||
};
|
||||
/*
|
||||
* Each registered constant [i.e: __TIME__, __DATE__, PHP_OS, INT_MAX, etc.] is stored
|
||||
* in an instance of the following structure.
|
||||
|
@ -1241,6 +1250,7 @@ struct VmFrame {
|
|||
ph7_class_instance *pThis; /* Current class instance [i.e: the '$this' variable].NULL otherwise */
|
||||
SySet sLocal; /* Local variables container (VmSlot instance) */
|
||||
ph7_vm *pVm; /* VM that own this frame */
|
||||
SyHash hConst; /* Constant hashtable for fast lookup */
|
||||
SyHash hVar; /* Variable hashtable for fast lookup */
|
||||
SySet sArg; /* Function arguments container */
|
||||
SySet sRef; /* Local reference table (VmSlot instance) */
|
||||
|
@ -1648,7 +1658,7 @@ PH7_PRIVATE sxi32 PH7_VmRefObjRemove(ph7_vm *pVm, sxu32 nIdx, SyHashEntry *pEntr
|
|||
PH7_PRIVATE sxi32 PH7_VmRefObjInstall(ph7_vm *pVm, sxu32 nIdx, SyHashEntry *pEntry, ph7_hashmap_node *pMapEntry, sxi32 iFlags);
|
||||
PH7_PRIVATE sxi32 PH7_VmPushFilePath(ph7_vm *pVm, const char *zPath, int nLen, sxu8 bMain, sxi32 *pNew);
|
||||
PH7_PRIVATE ph7_class *PH7_VmExtractClass(ph7_vm *pVm, const char *zName, sxu32 nByte, sxi32 iLoadable, sxi32 iNest);
|
||||
PH7_PRIVATE sxi32 PH7_VmRegisterConstant(ph7_vm *pVm, const SyString *pName, ProcConstant xExpand, void *pUserData);
|
||||
PH7_PRIVATE sxi32 PH7_VmRegisterConstant(ph7_vm *pVm, const SyString *pName, ProcConstant xExpand, void *pUserData, sxbool bGlobal);
|
||||
PH7_PRIVATE sxi32 PH7_VmInstallForeignFunction(ph7_vm *pVm, const SyString *pName, ProcHostFunction xFunc, void *pUserData);
|
||||
PH7_PRIVATE sxi32 PH7_VmInstallClass(ph7_vm *pVm, ph7_class *pClass);
|
||||
PH7_PRIVATE sxi32 PH7_VmBlobConsumer(const void *pSrc, unsigned int nLen, void *pUserData);
|
||||
|
|
Loading…
Reference in New Issue