Merge branch 'include_fix' into 'master'
This commit is contained in:
commit
deabbd5554
68
engine/api.c
68
engine/api.c
|
@ -604,6 +604,44 @@ int ph7_release(ph7 *pEngine) {
|
||||||
SyMemBackendPoolFree(&sMPGlobal.sAllocator, pEngine);
|
SyMemBackendPoolFree(&sMPGlobal.sAllocator, pEngine);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
int ph7_vm_init(
|
||||||
|
ph7 *pEngine, /* Running PH7 engine */
|
||||||
|
ph7_vm **ppOutVm /* OUT: A pointer to the virtual machine */
|
||||||
|
) {
|
||||||
|
ph7_vm *pVm;
|
||||||
|
int rc;
|
||||||
|
if(ppOutVm) {
|
||||||
|
*ppOutVm = 0;
|
||||||
|
}
|
||||||
|
/* Allocate a new virtual machine */
|
||||||
|
pVm = (ph7_vm *)SyMemBackendPoolAlloc(&pEngine->sAllocator, sizeof(ph7_vm));
|
||||||
|
if(pVm == 0) {
|
||||||
|
/* If the supplied memory subsystem is so sick that we are unable to allocate
|
||||||
|
* a tiny chunk of memory, there is no much we can do here. */
|
||||||
|
if(ppOutVm) {
|
||||||
|
*ppOutVm = 0;
|
||||||
|
}
|
||||||
|
return PH7_NOMEM;
|
||||||
|
}
|
||||||
|
/* Initialize the Virtual Machine */
|
||||||
|
rc = PH7_VmInit(pVm, &(*pEngine));
|
||||||
|
if(rc != PH7_OK) {
|
||||||
|
SyMemBackendPoolFree(&pEngine->sAllocator, pVm);
|
||||||
|
if(ppOutVm) {
|
||||||
|
*ppOutVm = 0;
|
||||||
|
}
|
||||||
|
return PH7_VM_ERR;
|
||||||
|
}
|
||||||
|
/* Reset the error message consumer */
|
||||||
|
SyBlobReset(&pEngine->xConf.sErrConsumer);
|
||||||
|
/* Set the default VM output consumer callback and it's
|
||||||
|
* private data. */
|
||||||
|
pVm->sVmConsumer.xConsumer = PH7_VmBlobConsumer;
|
||||||
|
pVm->sVmConsumer.pUserData = &pVm->sConsumer;
|
||||||
|
/* Point to the freshly created VM */
|
||||||
|
*ppOutVm = pVm;
|
||||||
|
return PH7_OK;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Compile a raw PHP script.
|
* Compile a raw PHP script.
|
||||||
* To execute a PHP code, it must first be compiled into a byte-code program using this routine.
|
* To execute a PHP code, it must first be compiled into a byte-code program using this routine.
|
||||||
|
@ -621,33 +659,14 @@ static sxi32 ProcessScript(
|
||||||
sxi32 iFlags, /* Compile-time flags */
|
sxi32 iFlags, /* Compile-time flags */
|
||||||
const char *zFilePath /* File path if script come from a file. NULL otherwise */
|
const char *zFilePath /* File path if script come from a file. NULL otherwise */
|
||||||
) {
|
) {
|
||||||
ph7_vm *pVm;
|
ph7_vm *pVm = *ppVm;
|
||||||
int iFileDir, rc;
|
int iFileDir, rc;
|
||||||
char *pFileDir, *fFilePath[PATH_MAX + 1];
|
char *pFileDir, *fFilePath[PATH_MAX + 1];
|
||||||
char *pFilePath[PATH_MAX + 1];
|
char *pFilePath[PATH_MAX + 1];
|
||||||
/* Allocate a new virtual machine */
|
|
||||||
pVm = (ph7_vm *)SyMemBackendPoolAlloc(&pEngine->sAllocator, sizeof(ph7_vm));
|
|
||||||
if(pVm == 0) {
|
|
||||||
/* If the supplied memory subsystem is so sick that we are unable to allocate
|
|
||||||
* a tiny chunk of memory, there is no much we can do here. */
|
|
||||||
if(ppVm) {
|
|
||||||
*ppVm = 0;
|
|
||||||
}
|
|
||||||
return PH7_NOMEM;
|
|
||||||
}
|
|
||||||
if(iFlags < 0) {
|
if(iFlags < 0) {
|
||||||
/* Default compile-time flags */
|
/* Default compile-time flags */
|
||||||
iFlags = 0;
|
iFlags = 0;
|
||||||
}
|
}
|
||||||
/* Initialize the Virtual Machine */
|
|
||||||
rc = PH7_VmInit(pVm, &(*pEngine));
|
|
||||||
if(rc != PH7_OK) {
|
|
||||||
SyMemBackendPoolFree(&pEngine->sAllocator, pVm);
|
|
||||||
if(ppVm) {
|
|
||||||
*ppVm = 0;
|
|
||||||
}
|
|
||||||
return PH7_VM_ERR;
|
|
||||||
}
|
|
||||||
/* Install local import path which is the current directory */
|
/* Install local import path which is the current directory */
|
||||||
ph7_vm_config(pVm, PH7_VM_CONFIG_IMPORT_PATH, "./");
|
ph7_vm_config(pVm, PH7_VM_CONFIG_IMPORT_PATH, "./");
|
||||||
if(zFilePath && SyRealPath(zFilePath, fFilePath) == PH7_OK) {
|
if(zFilePath && SyRealPath(zFilePath, fFilePath) == PH7_OK) {
|
||||||
|
@ -660,8 +679,6 @@ static sxi32 ProcessScript(
|
||||||
/* Push processed file path */
|
/* Push processed file path */
|
||||||
PH7_VmPushFilePath(pVm, pFilePath, -1, TRUE, 0);
|
PH7_VmPushFilePath(pVm, pFilePath, -1, TRUE, 0);
|
||||||
}
|
}
|
||||||
/* Reset the error message consumer */
|
|
||||||
SyBlobReset(&pEngine->xConf.sErrConsumer);
|
|
||||||
/* Compile the script */
|
/* Compile the script */
|
||||||
PH7_CompileScript(pVm, &(*pScript), iFlags);
|
PH7_CompileScript(pVm, &(*pScript), iFlags);
|
||||||
if(pVm->sCodeGen.nErr > 0 || pVm == 0) {
|
if(pVm->sCodeGen.nErr > 0 || pVm == 0) {
|
||||||
|
@ -691,8 +708,6 @@ static sxi32 ProcessScript(
|
||||||
/* Script successfully compiled,link to the list of active virtual machines */
|
/* Script successfully compiled,link to the list of active virtual machines */
|
||||||
MACRO_LD_PUSH(pEngine->pVms, pVm);
|
MACRO_LD_PUSH(pEngine->pVms, pVm);
|
||||||
pEngine->iVm++;
|
pEngine->iVm++;
|
||||||
/* Point to the freshly created VM */
|
|
||||||
*ppVm = pVm;
|
|
||||||
/* Ready to execute PH7 bytecode */
|
/* Ready to execute PH7 bytecode */
|
||||||
return PH7_OK;
|
return PH7_OK;
|
||||||
Release:
|
Release:
|
||||||
|
@ -772,9 +787,6 @@ int ph7_compile_v2(ph7 *pEngine, const char *zSource, int nLen, ph7_vm **ppOutVm
|
||||||
int ph7_compile_file(ph7 *pEngine, const char *zFilePath, ph7_vm **ppOutVm, int iFlags) {
|
int ph7_compile_file(ph7 *pEngine, const char *zFilePath, ph7_vm **ppOutVm, int iFlags) {
|
||||||
const ph7_vfs *pVfs;
|
const ph7_vfs *pVfs;
|
||||||
int rc;
|
int rc;
|
||||||
if(ppOutVm) {
|
|
||||||
*ppOutVm = 0;
|
|
||||||
}
|
|
||||||
rc = PH7_OK; /* cc warning */
|
rc = PH7_OK; /* cc warning */
|
||||||
if(PH7_ENGINE_MISUSE(pEngine) || SX_EMPTY_STR(zFilePath)) {
|
if(PH7_ENGINE_MISUSE(pEngine) || SX_EMPTY_STR(zFilePath)) {
|
||||||
return PH7_CORRUPT;
|
return PH7_CORRUPT;
|
||||||
|
@ -859,7 +871,7 @@ int ph7_vm_config(ph7_vm *pVm, int iConfigOp, ...) {
|
||||||
return PH7_ABORT; /* Another thread have released this instance */
|
return PH7_ABORT; /* Another thread have released this instance */
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* Confiugure the virtual machine */
|
/* Configure the virtual machine */
|
||||||
va_start(ap, iConfigOp);
|
va_start(ap, iConfigOp);
|
||||||
rc = PH7_VmConfigure(&(*pVm), iConfigOp, ap);
|
rc = PH7_VmConfigure(&(*pVm), iConfigOp, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
|
@ -4006,12 +4006,27 @@ Synchronize:
|
||||||
static sxi32 PH7_CompileClassInterface(ph7_gen_state *pGen) {
|
static sxi32 PH7_CompileClassInterface(ph7_gen_state *pGen) {
|
||||||
sxu32 nLine = pGen->pIn->nLine;
|
sxu32 nLine = pGen->pIn->nLine;
|
||||||
ph7_class *pClass, *pBase;
|
ph7_class *pClass, *pBase;
|
||||||
|
ph7_class_info *pClassInfo;
|
||||||
SyToken *pEnd, *pTmp;
|
SyToken *pEnd, *pTmp;
|
||||||
SyString *pName;
|
SyString *pName;
|
||||||
sxi32 nKwrd;
|
sxi32 nKwrd;
|
||||||
sxi32 rc;
|
sxi32 rc;
|
||||||
|
sxi32 iP1 = 0;
|
||||||
/* Jump the 'interface' keyword */
|
/* Jump the 'interface' keyword */
|
||||||
pGen->pIn++;
|
pGen->pIn++;
|
||||||
|
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_ID) == 0) {
|
||||||
|
/* Syntax error */
|
||||||
|
rc = PH7_GenCompileError(pGen, E_ERROR, nLine, "Invalid interface name");
|
||||||
|
if(rc == SXERR_ABORT) {
|
||||||
|
/* Error count limit reached,abort immediately */
|
||||||
|
return SXERR_ABORT;
|
||||||
|
}
|
||||||
|
/* Synchronize with the first semi-colon or curly braces */
|
||||||
|
while(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & (PH7_TK_OCB/*'{'*/ | PH7_TK_SEMI/*';'*/)) == 0) {
|
||||||
|
pGen->pIn++;
|
||||||
|
}
|
||||||
|
return SXRET_OK;
|
||||||
|
}
|
||||||
/* Extract interface name */
|
/* Extract interface name */
|
||||||
pName = &pGen->pIn->sData;
|
pName = &pGen->pIn->sData;
|
||||||
/* Advance the stream cursor */
|
/* Advance the stream cursor */
|
||||||
|
@ -4022,16 +4037,23 @@ static sxi32 PH7_CompileClassInterface(ph7_gen_state *pGen) {
|
||||||
PH7_GenCompileError(pGen, E_ERROR, nLine, "Fatal, PH7 is running out of memory");
|
PH7_GenCompileError(pGen, E_ERROR, nLine, "Fatal, PH7 is running out of memory");
|
||||||
return SXERR_ABORT;
|
return SXERR_ABORT;
|
||||||
}
|
}
|
||||||
|
/* Obtain a raw class inheritance storage */
|
||||||
|
pClassInfo = PH7_NewClassInfo(pGen->pVm, pName);
|
||||||
|
if(pClassInfo == 0) {
|
||||||
|
PH7_GenCompileError(pGen, E_ERROR, nLine, "Fatal, PH7 is running out of memory");
|
||||||
|
return SXERR_ABORT;
|
||||||
|
}
|
||||||
/* Mark as an interface */
|
/* Mark as an interface */
|
||||||
pClass->iFlags = PH7_CLASS_INTERFACE;
|
pClass->iFlags = PH7_CLASS_INTERFACE;
|
||||||
/* Assume no base class is given */
|
/* Assume no base class is given */
|
||||||
pBase = 0;
|
pBase = 0;
|
||||||
if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_KEYWORD)) {
|
if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_KEYWORD)) {
|
||||||
|
SyString pBaseName;
|
||||||
nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData);
|
nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData);
|
||||||
if(nKwrd == PH7_TKWRD_EXTENDS /* interface b extends a */) {
|
if(nKwrd == PH7_TKWRD_EXTENDS /* interface b extends a */) {
|
||||||
SyString *pBaseName;
|
|
||||||
/* Extract base interface */
|
/* Extract base interface */
|
||||||
pGen->pIn++;
|
pGen->pIn++;
|
||||||
|
for(;;) {
|
||||||
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_ID) == 0) {
|
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_ID) == 0) {
|
||||||
/* Syntax error */
|
/* Syntax error */
|
||||||
rc = PH7_GenCompileError(pGen, E_ERROR, nLine,
|
rc = PH7_GenCompileError(pGen, E_ERROR, nLine,
|
||||||
|
@ -4044,22 +4066,20 @@ static sxi32 PH7_CompileClassInterface(ph7_gen_state *pGen) {
|
||||||
}
|
}
|
||||||
return SXRET_OK;
|
return SXRET_OK;
|
||||||
}
|
}
|
||||||
pBaseName = &pGen->pIn->sData;
|
/* Extract base class name */
|
||||||
pBase = PH7_VmExtractClass(pGen->pVm, pBaseName->zString, pBaseName->nByte, FALSE, 0);
|
char *sName = SyMemBackendStrDup(&pGen->pVm->sAllocator, pGen->pIn->sData.zString, pGen->pIn->sData.nByte);
|
||||||
/* Only interfaces is allowed */
|
SyStringInitFromBuf(&pBaseName, sName, SyStrlen(sName));
|
||||||
while(pBase && (pBase->iFlags & PH7_CLASS_INTERFACE) == 0) {
|
/* Register inherited class */
|
||||||
pBase = pBase->pNextName;
|
SySetPut(&pClassInfo->sExtends, (const void *)&pBaseName);
|
||||||
}
|
|
||||||
if(pBase == 0) {
|
|
||||||
/* Inexistant interface */
|
|
||||||
rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, "Inexistant base interface '%z'", pBaseName);
|
|
||||||
if(rc == SXERR_ABORT) {
|
|
||||||
/* Error count limit reached,abort immediately */
|
|
||||||
return SXERR_ABORT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Advance the stream cursor */
|
/* Advance the stream cursor */
|
||||||
pGen->pIn++;
|
pGen->pIn++;
|
||||||
|
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_COMMA) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Jump the comma operator */
|
||||||
|
pGen->pIn++;
|
||||||
|
}
|
||||||
|
iP1 = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_OCB /*'{'*/) == 0) {
|
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_OCB /*'{'*/) == 0) {
|
||||||
|
@ -4191,9 +4211,9 @@ static sxi32 PH7_CompileClassInterface(ph7_gen_state *pGen) {
|
||||||
}
|
}
|
||||||
/* Install the interface */
|
/* Install the interface */
|
||||||
rc = PH7_VmInstallClass(pGen->pVm, pClass);
|
rc = PH7_VmInstallClass(pGen->pVm, pClass);
|
||||||
if(rc == SXRET_OK && pBase) {
|
if(iP1) {
|
||||||
/* Inherit from the base interface */
|
/* Emit the INTERFACE_INIT instruction only if there is such a need */
|
||||||
rc = PH7_ClassInterfaceInherit(pClass, pBase);
|
PH7_VmEmitInstr(pGen->pVm, PH7_OP_INTERFACE_INIT, iP1, 0, pClassInfo, 0);
|
||||||
}
|
}
|
||||||
if(rc != SXRET_OK) {
|
if(rc != SXRET_OK) {
|
||||||
PH7_GenCompileError(pGen, E_ERROR, nLine, "Fatal, PH7 is running out of memory");
|
PH7_GenCompileError(pGen, E_ERROR, nLine, "Fatal, PH7 is running out of memory");
|
||||||
|
@ -4222,13 +4242,15 @@ done:
|
||||||
static sxi32 GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) {
|
static sxi32 GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) {
|
||||||
sxu32 nLine = pGen->pIn->nLine;
|
sxu32 nLine = pGen->pIn->nLine;
|
||||||
ph7_class *pClass, *pBase;
|
ph7_class *pClass, *pBase;
|
||||||
|
ph7_class_info *pClassInfo;
|
||||||
SyToken *pEnd, *pTmp;
|
SyToken *pEnd, *pTmp;
|
||||||
sxi32 iProtection;
|
sxi32 iProtection;
|
||||||
SySet aInterfaces;
|
|
||||||
sxi32 iAttrflags;
|
sxi32 iAttrflags;
|
||||||
SyString *pName;
|
SyString *pName;
|
||||||
sxi32 nKwrd;
|
sxi32 nKwrd;
|
||||||
sxi32 rc;
|
sxi32 rc;
|
||||||
|
sxi32 iP1 = 0;
|
||||||
|
sxu32 iP2 = 0;
|
||||||
/* Jump the 'class' keyword */
|
/* Jump the 'class' keyword */
|
||||||
pGen->pIn++;
|
pGen->pIn++;
|
||||||
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_ID) == 0) {
|
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_ID) == 0) {
|
||||||
|
@ -4254,15 +4276,20 @@ static sxi32 GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) {
|
||||||
PH7_GenCompileError(pGen, E_ERROR, nLine, "Fatal, PH7 is running out of memory");
|
PH7_GenCompileError(pGen, E_ERROR, nLine, "Fatal, PH7 is running out of memory");
|
||||||
return SXERR_ABORT;
|
return SXERR_ABORT;
|
||||||
}
|
}
|
||||||
/* implemented interfaces container */
|
/* Obtain a raw class inheritance storage */
|
||||||
SySetInit(&aInterfaces, &pGen->pVm->sAllocator, sizeof(ph7_class *));
|
pClassInfo = PH7_NewClassInfo(pGen->pVm, pName);
|
||||||
|
if(pClassInfo == 0) {
|
||||||
|
PH7_GenCompileError(pGen, E_ERROR, nLine, "Fatal, PH7 is running out of memory");
|
||||||
|
return SXERR_ABORT;
|
||||||
|
}
|
||||||
/* Assume a standalone class */
|
/* Assume a standalone class */
|
||||||
pBase = 0;
|
pBase = 0;
|
||||||
if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_KEYWORD)) {
|
if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_KEYWORD)) {
|
||||||
SyString *pBaseName;
|
SyString pBaseName;
|
||||||
nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData);
|
nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData);
|
||||||
if(nKwrd == PH7_TKWRD_EXTENDS /* class b extends a */) {
|
if(nKwrd == PH7_TKWRD_EXTENDS /* class b extends a */) {
|
||||||
pGen->pIn++; /* Advance the stream cursor */
|
pGen->pIn++; /* Advance the stream cursor */
|
||||||
|
for(;;) {
|
||||||
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_ID) == 0) {
|
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_ID) == 0) {
|
||||||
/* Syntax error */
|
/* Syntax error */
|
||||||
rc = PH7_GenCompileError(pGen, E_ERROR, nLine,
|
rc = PH7_GenCompileError(pGen, E_ERROR, nLine,
|
||||||
|
@ -4276,36 +4303,22 @@ static sxi32 GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) {
|
||||||
return SXRET_OK;
|
return SXRET_OK;
|
||||||
}
|
}
|
||||||
/* Extract base class name */
|
/* Extract base class name */
|
||||||
pBaseName = &pGen->pIn->sData;
|
char *sName = SyMemBackendStrDup(&pGen->pVm->sAllocator, pGen->pIn->sData.zString, pGen->pIn->sData.nByte);
|
||||||
/* Perform the query */
|
SyStringInitFromBuf(&pBaseName, sName, SyStrlen(sName));
|
||||||
pBase = PH7_VmExtractClass(pGen->pVm, pBaseName->zString, pBaseName->nByte, FALSE, 0);
|
/* Register inherited class */
|
||||||
/* Interfaces are not allowed */
|
SySetPut(&pClassInfo->sExtends, (const void *)&pBaseName);
|
||||||
while(pBase && (pBase->iFlags & PH7_CLASS_INTERFACE)) {
|
|
||||||
pBase = pBase->pNextName;
|
|
||||||
}
|
|
||||||
if(pBase == 0) {
|
|
||||||
/* Inexistant base class */
|
|
||||||
rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, "Inexistant base class '%z'", pBaseName);
|
|
||||||
if(rc == SXERR_ABORT) {
|
|
||||||
/* Error count limit reached,abort immediately */
|
|
||||||
return SXERR_ABORT;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(pBase->iFlags & PH7_CLASS_FINAL) {
|
|
||||||
rc = PH7_GenCompileError(pGen, E_ERROR, nLine,
|
|
||||||
"Class '%z' may not inherit from final class '%z'", pName, &pBase->sName);
|
|
||||||
if(rc == SXERR_ABORT) {
|
|
||||||
/* Error count limit reached,abort immediately */
|
|
||||||
return SXERR_ABORT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Advance the stream cursor */
|
/* Advance the stream cursor */
|
||||||
pGen->pIn++;
|
pGen->pIn++;
|
||||||
|
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_COMMA) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Jump the comma operator */
|
||||||
|
pGen->pIn++;
|
||||||
|
}
|
||||||
|
iP1 = 1;
|
||||||
}
|
}
|
||||||
if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_KEYWORD) && SX_PTR_TO_INT(pGen->pIn->pUserData) == PH7_TKWRD_IMPLEMENTS) {
|
if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_KEYWORD) && SX_PTR_TO_INT(pGen->pIn->pUserData) == PH7_TKWRD_IMPLEMENTS) {
|
||||||
ph7_class *pInterface;
|
SyString pIntName;
|
||||||
SyString *pIntName;
|
|
||||||
/* Interface implementation */
|
/* Interface implementation */
|
||||||
pGen->pIn++; /* Advance the stream cursor */
|
pGen->pIn++; /* Advance the stream cursor */
|
||||||
for(;;) {
|
for(;;) {
|
||||||
|
@ -4314,38 +4327,27 @@ static sxi32 GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) {
|
||||||
rc = PH7_GenCompileError(pGen, E_ERROR, nLine,
|
rc = PH7_GenCompileError(pGen, E_ERROR, nLine,
|
||||||
"Expected 'interface_name' after 'implements' keyword inside class '%z' declaration",
|
"Expected 'interface_name' after 'implements' keyword inside class '%z' declaration",
|
||||||
pName);
|
pName);
|
||||||
|
SyMemBackendPoolFree(&pGen->pVm->sAllocator, pClass);
|
||||||
if(rc == SXERR_ABORT) {
|
if(rc == SXERR_ABORT) {
|
||||||
/* Error count limit reached,abort immediately */
|
/* Error count limit reached,abort immediately */
|
||||||
return SXERR_ABORT;
|
return SXERR_ABORT;
|
||||||
}
|
}
|
||||||
break;
|
return SXRET_OK;
|
||||||
}
|
}
|
||||||
/* Extract interface name */
|
/* Extract interface name */
|
||||||
pIntName = &pGen->pIn->sData;
|
char *sName = SyMemBackendStrDup(&pGen->pVm->sAllocator, pGen->pIn->sData.zString, pGen->pIn->sData.nByte);
|
||||||
/* Make sure the interface is already defined */
|
SyStringInitFromBuf(&pIntName, sName, SyStrlen(sName));
|
||||||
pInterface = PH7_VmExtractClass(pGen->pVm, pIntName->zString, pIntName->nByte, FALSE, 0);
|
/* Register inherited class */
|
||||||
/* Only interfaces are allowed */
|
SySetPut(&pClassInfo->sImplements, (const void *)&pIntName);
|
||||||
while(pInterface && (pInterface->iFlags & PH7_CLASS_INTERFACE) == 0) {
|
|
||||||
pInterface = pInterface->pNextName;
|
|
||||||
}
|
|
||||||
if(pInterface == 0) {
|
|
||||||
/* Inexistant interface */
|
|
||||||
rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, "Inexistant base interface '%z'", pIntName);
|
|
||||||
if(rc == SXERR_ABORT) {
|
|
||||||
/* Error count limit reached,abort immediately */
|
|
||||||
return SXERR_ABORT;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Register interface */
|
|
||||||
SySetPut(&aInterfaces, (const void *)&pInterface);
|
|
||||||
}
|
|
||||||
/* Advance the stream cursor */
|
/* Advance the stream cursor */
|
||||||
pGen->pIn++;
|
pGen->pIn++;
|
||||||
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_COMMA) == 0) {
|
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_COMMA) == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pGen->pIn++;/* Jump the comma */
|
/* Jump the comma */
|
||||||
|
pGen->pIn++;
|
||||||
}
|
}
|
||||||
|
iP2 = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_OCB /*'{'*/) == 0) {
|
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_OCB /*'{'*/) == 0) {
|
||||||
|
@ -4585,23 +4587,10 @@ static sxi32 GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) {
|
||||||
}
|
}
|
||||||
/* Install the class */
|
/* Install the class */
|
||||||
rc = PH7_VmInstallClass(pGen->pVm, pClass);
|
rc = PH7_VmInstallClass(pGen->pVm, pClass);
|
||||||
if(rc == SXRET_OK) {
|
if(iP1 || iP2) {
|
||||||
ph7_class **apInterface;
|
/* Emit the CLASS_INIT instruction only if there is such a need */
|
||||||
sxu32 n;
|
PH7_VmEmitInstr(pGen->pVm, PH7_OP_CLASS_INIT, iP1, iP2, pClassInfo, 0);
|
||||||
if(pBase) {
|
|
||||||
/* Inherit from base class and mark as a subclass */
|
|
||||||
rc = PH7_ClassInherit(&(*pGen), pClass, pBase);
|
|
||||||
}
|
}
|
||||||
apInterface = (ph7_class **)SySetBasePtr(&aInterfaces);
|
|
||||||
for(n = 0 ; n < SySetUsed(&aInterfaces) ; n++) {
|
|
||||||
/* Implements one or more interface */
|
|
||||||
rc = PH7_ClassImplement(pClass, apInterface[n]);
|
|
||||||
if(rc != SXRET_OK) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SySetRelease(&aInterfaces);
|
|
||||||
if(rc != SXRET_OK) {
|
if(rc != SXRET_OK) {
|
||||||
PH7_GenCompileError(pGen, E_ERROR, nLine, "Fatal, PH7 is running out of memory");
|
PH7_GenCompileError(pGen, E_ERROR, nLine, "Fatal, PH7 is running out of memory");
|
||||||
return SXERR_ABORT;
|
return SXERR_ABORT;
|
||||||
|
|
60
engine/oop.c
60
engine/oop.c
|
@ -15,6 +15,33 @@
|
||||||
/*
|
/*
|
||||||
* This file implement an Object Oriented (OO) subsystem for the PH7 engine.
|
* This file implement an Object Oriented (OO) subsystem for the PH7 engine.
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
|
* Create an empty class inheritance storage.
|
||||||
|
* Return a pointer to a storage (ph7_class_info instance) on success. NULL otherwise.
|
||||||
|
*/
|
||||||
|
PH7_PRIVATE ph7_class_info *PH7_NewClassInfo(ph7_vm *pVm, const SyString *pName) {
|
||||||
|
ph7_class_info *pClassInfo;
|
||||||
|
char *zName;
|
||||||
|
/* Allocate a new instance */
|
||||||
|
pClassInfo = (ph7_class_info *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(ph7_class_info));
|
||||||
|
if(pClassInfo == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Zero the structure */
|
||||||
|
SyZero(pClassInfo, sizeof(ph7_class_info));
|
||||||
|
/* Duplicate class name */
|
||||||
|
zName = SyMemBackendStrDup(&pVm->sAllocator, pName->zString, pName->nByte);
|
||||||
|
if(zName == 0) {
|
||||||
|
SyMemBackendPoolFree(&pVm->sAllocator, pClassInfo);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Initialize the class information storage */
|
||||||
|
SyStringInitFromBuf(&pClassInfo->sName, zName, pName->nByte);
|
||||||
|
SySetInit(&pClassInfo->sExtends, &pVm->sAllocator, sizeof(SyString));
|
||||||
|
SySetInit(&pClassInfo->sImplements, &pVm->sAllocator, sizeof(SyString));
|
||||||
|
/* All done */
|
||||||
|
return pClassInfo;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Create an empty class.
|
* Create an empty class.
|
||||||
* Return a pointer to a raw class (ph7_class instance) on success. NULL otherwise.
|
* Return a pointer to a raw class (ph7_class instance) on success. NULL otherwise.
|
||||||
|
@ -152,7 +179,7 @@ PH7_PRIVATE ph7_class_attr *PH7_ClassExtractAttribute(ph7_class *pClass, const c
|
||||||
/* No such entry */
|
/* No such entry */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* Point to the desierd method */
|
/* Point to the desired method */
|
||||||
return (ph7_class_attr *)pEntry->pUserData;
|
return (ph7_class_attr *)pEntry->pUserData;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -216,7 +243,7 @@ PH7_PRIVATE sxi32 PH7_ClassInstallMethod(ph7_class *pClass, ph7_class_method *pM
|
||||||
* Any other return value indicates failure and the upper layer must generate an appropriate
|
* Any other return value indicates failure and the upper layer must generate an appropriate
|
||||||
* error message.
|
* error message.
|
||||||
*/
|
*/
|
||||||
PH7_PRIVATE sxi32 PH7_ClassInherit(ph7_gen_state *pGen, ph7_class *pSub, ph7_class *pBase) {
|
PH7_PRIVATE sxi32 PH7_ClassInherit(ph7_vm *pVm, ph7_class *pSub, ph7_class *pBase) {
|
||||||
ph7_class_method *pMeth;
|
ph7_class_method *pMeth;
|
||||||
ph7_class_attr *pAttr;
|
ph7_class_attr *pAttr;
|
||||||
SyHashEntry *pEntry;
|
SyHashEntry *pEntry;
|
||||||
|
@ -234,12 +261,12 @@ PH7_PRIVATE sxi32 PH7_ClassInherit(ph7_gen_state *pGen, ph7_class *pSub, ph7_cla
|
||||||
pAttr = (ph7_class_attr *)pEntry->pUserData;
|
pAttr = (ph7_class_attr *)pEntry->pUserData;
|
||||||
pName = &pAttr->sName;
|
pName = &pAttr->sName;
|
||||||
if((pEntry = SyHashGet(&pSub->hAttr, (const void *)pName->zString, pName->nByte)) != 0) {
|
if((pEntry = SyHashGet(&pSub->hAttr, (const void *)pName->zString, pName->nByte)) != 0) {
|
||||||
if(pAttr->iProtection == PH7_CLASS_PROT_PRIVATE &&
|
if(pAttr->iProtection == PH7_CLASS_PROT_PRIVATE && ((ph7_class_attr *)pEntry->pUserData)->iProtection != PH7_CLASS_PROT_PUBLIC) {
|
||||||
((ph7_class_attr *)pEntry->pUserData)->iProtection != PH7_CLASS_PROT_PUBLIC) {
|
|
||||||
/* Cannot redeclare private attribute */
|
/* Cannot redeclare private attribute */
|
||||||
PH7_GenCompileError(&(*pGen), E_WARNING, ((ph7_class_attr *)pEntry->pUserData)->nLine,
|
rc = VmErrorFormat(pVm, PH7_CTX_ERR, "Private attribute '%z::%z' redeclared inside child class '%z'", &pBase->sName, pName, &pSub->sName);
|
||||||
"Private attribute '%z::%z' redeclared inside child class '%z'",
|
if(rc == SXERR_ABORT) {
|
||||||
&pBase->sName, pName, &pSub->sName);
|
return SXERR_ABORT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -259,9 +286,7 @@ PH7_PRIVATE sxi32 PH7_ClassInherit(ph7_gen_state *pGen, ph7_class *pSub, ph7_cla
|
||||||
if((pEntry = SyHashGet(&pSub->hMethod, (const void *)pName->zString, pName->nByte)) != 0) {
|
if((pEntry = SyHashGet(&pSub->hMethod, (const void *)pName->zString, pName->nByte)) != 0) {
|
||||||
if(pMeth->iFlags & PH7_CLASS_ATTR_FINAL) {
|
if(pMeth->iFlags & PH7_CLASS_ATTR_FINAL) {
|
||||||
/* Cannot Overwrite final method */
|
/* Cannot Overwrite final method */
|
||||||
rc = PH7_GenCompileError(&(*pGen), E_ERROR, ((ph7_class_method *)pEntry->pUserData)->nLine,
|
rc = VmErrorFormat(&(*pVm), PH7_CTX_ERR, "Cannot overwrite final method '%z:%z()' inside child class '%z'", &pBase->sName, pName, &pSub->sName);
|
||||||
"Cannot Overwrite final method '%z:%z' inside child class '%z'",
|
|
||||||
&pBase->sName, pName, &pSub->sName);
|
|
||||||
if(rc == SXERR_ABORT) {
|
if(rc == SXERR_ABORT) {
|
||||||
return SXERR_ABORT;
|
return SXERR_ABORT;
|
||||||
}
|
}
|
||||||
|
@ -270,9 +295,10 @@ PH7_PRIVATE sxi32 PH7_ClassInherit(ph7_gen_state *pGen, ph7_class *pSub, ph7_cla
|
||||||
} else {
|
} else {
|
||||||
if(pMeth->iFlags & PH7_CLASS_ATTR_ABSTRACT) {
|
if(pMeth->iFlags & PH7_CLASS_ATTR_ABSTRACT) {
|
||||||
/* Abstract method must be defined in the child class */
|
/* Abstract method must be defined in the child class */
|
||||||
PH7_GenCompileError(&(*pGen), E_WARNING, pMeth->nLine,
|
rc = VmErrorFormat(&(*pVm), PH7_CTX_ERR, "Abstract method '%z:%z()' must be defined inside child class '%z'", &pBase->sName, pName, &pSub->sName);
|
||||||
"Abstract method '%z:%z' must be defined inside child class '%z'",
|
if(rc == SXERR_ABORT) {
|
||||||
&pBase->sName, pName, &pSub->sName);
|
return SXERR_ABORT;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -936,7 +962,7 @@ PH7_PRIVATE sxi32 PH7_ClassInstanceDump(SyBlob *pOut, ph7_class_instance *pThis,
|
||||||
* The above example will output:
|
* The above example will output:
|
||||||
* Hello
|
* Hello
|
||||||
*
|
*
|
||||||
* Note that PH7 does not support all the magical method and introudces __toFloat(),__toInt()
|
* Note that PH7 does not support all the magical method and introduces __toFloat(),__toInt()
|
||||||
* which have the same behaviour as __toString() but for float and integer types
|
* which have the same behaviour as __toString() but for float and integer types
|
||||||
* respectively.
|
* respectively.
|
||||||
* Refer to the official documentation for more information.
|
* Refer to the official documentation for more information.
|
||||||
|
@ -1011,7 +1037,7 @@ PH7_PRIVATE ph7_value *PH7_ClassInstanceExtractAttrValue(ph7_class_instance *pTh
|
||||||
* int(991)
|
* int(991)
|
||||||
* }
|
* }
|
||||||
* You have noticed that PH7 allow class attributes [i.e: $a,$c,$d in the example above]
|
* You have noticed that PH7 allow class attributes [i.e: $a,$c,$d in the example above]
|
||||||
* have any complex expression (even function calls/Annonymous functions) as their default
|
* have any complex expression (even function calls/anonymous functions) as their default
|
||||||
* value unlike the standard PHP engine.
|
* value unlike the standard PHP engine.
|
||||||
* This is a very powerful feature that you have to look at.
|
* This is a very powerful feature that you have to look at.
|
||||||
*/
|
*/
|
||||||
|
@ -1085,7 +1111,7 @@ PH7_PRIVATE sxi32 PH7_ClassInstanceWalk(
|
||||||
return SXRET_OK;
|
return SXRET_OK;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Extract a class atrribute value.
|
* Extract a class attribute value.
|
||||||
* Return a pointer to the attribute value on success. Otherwise NULL.
|
* Return a pointer to the attribute value on success. Otherwise NULL.
|
||||||
* Note:
|
* Note:
|
||||||
* Access to static and constant attribute is not allowed. That is,the function
|
* Access to static and constant attribute is not allowed. That is,the function
|
||||||
|
@ -1101,7 +1127,7 @@ PH7_PRIVATE ph7_value *PH7_ClassInstanceFetchAttr(ph7_class_instance *pThis, con
|
||||||
/* No such attribute */
|
/* No such attribute */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* Point to the class atrribute */
|
/* Point to the class attribute */
|
||||||
pAttr = (VmClassAttr *)pEntry->pUserData;
|
pAttr = (VmClassAttr *)pEntry->pUserData;
|
||||||
/* Check if we are dealing with a static/constant attribute */
|
/* Check if we are dealing with a static/constant attribute */
|
||||||
if(pAttr->pAttr->iFlags & (PH7_CLASS_ATTR_CONSTANT | PH7_CLASS_ATTR_STATIC)) {
|
if(pAttr->pAttr->iFlags & (PH7_CLASS_ATTR_CONSTANT | PH7_CLASS_ATTR_STATIC)) {
|
||||||
|
|
123
engine/vm.c
123
engine/vm.c
|
@ -384,13 +384,8 @@ PH7_PRIVATE sxi32 PH7_VmInstallClass(
|
||||||
/* Check for duplicates */
|
/* Check for duplicates */
|
||||||
pEntry = SyHashGet(&pVm->hClass, (const void *)pName->zString, pName->nByte);
|
pEntry = SyHashGet(&pVm->hClass, (const void *)pName->zString, pName->nByte);
|
||||||
if(pEntry) {
|
if(pEntry) {
|
||||||
ph7_class *pLink = (ph7_class *)pEntry->pUserData;
|
PH7_VmThrowError(&(*pVm), 0, PH7_CTX_ERR, "Cannot declare class, because the name is already in use");
|
||||||
/* Link entry with the same name */
|
|
||||||
pClass->pNextName = pLink;
|
|
||||||
pEntry->pUserData = pClass;
|
|
||||||
return SXRET_OK;
|
|
||||||
}
|
}
|
||||||
pClass->pNextName = 0;
|
|
||||||
/* Perform a simple hashtable insertion */
|
/* Perform a simple hashtable insertion */
|
||||||
rc = SyHashInsert(&pVm->hClass, (const void *)pName->zString, pName->nByte, pClass);
|
rc = SyHashInsert(&pVm->hClass, (const void *)pName->zString, pName->nByte, pClass);
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -632,7 +627,7 @@ static int VmOverloadCompare(SyString *pFirst, SyString *pSecond) {
|
||||||
}
|
}
|
||||||
/* Forward declaration */
|
/* Forward declaration */
|
||||||
static sxi32 VmLocalExec(ph7_vm *pVm, SySet *pByteCode, ph7_value *pResult);
|
static sxi32 VmLocalExec(ph7_vm *pVm, SySet *pByteCode, ph7_value *pResult);
|
||||||
static sxi32 VmErrorFormat(ph7_vm *pVm, sxi32 iErr, const char *zFormat, ...);
|
sxi32 VmErrorFormat(ph7_vm *pVm, sxi32 iErr, const char *zFormat, ...);
|
||||||
/*
|
/*
|
||||||
* Select the appropriate VM function for the current call context.
|
* Select the appropriate VM function for the current call context.
|
||||||
* This is the implementation of the powerful 'function overloading' feature
|
* This is the implementation of the powerful 'function overloading' feature
|
||||||
|
@ -1412,10 +1407,6 @@ PH7_PRIVATE sxi32 PH7_VmMakeReady(
|
||||||
if(pVm->aOps == 0) {
|
if(pVm->aOps == 0) {
|
||||||
return SXERR_MEM;
|
return SXERR_MEM;
|
||||||
}
|
}
|
||||||
/* Set the default VM output consumer callback and it's
|
|
||||||
* private data. */
|
|
||||||
pVm->sVmConsumer.xConsumer = PH7_VmBlobConsumer;
|
|
||||||
pVm->sVmConsumer.pUserData = &pVm->sConsumer;
|
|
||||||
/* Allocate the reference table */
|
/* Allocate the reference table */
|
||||||
pVm->nRefSize = 0x10; /* Must be a power of two for fast arithemtic */
|
pVm->nRefSize = 0x10; /* Must be a power of two for fast arithemtic */
|
||||||
pVm->apRefObj = (VmRefObj **)SyMemBackendAlloc(&pVm->sAllocator, sizeof(VmRefObj *) * pVm->nRefSize);
|
pVm->apRefObj = (VmRefObj **)SyMemBackendAlloc(&pVm->sAllocator, sizeof(VmRefObj *) * pVm->nRefSize);
|
||||||
|
@ -2276,7 +2267,7 @@ static sxi32 VmThrowErrorAp(
|
||||||
* Simple boring wrapper function.
|
* Simple boring wrapper function.
|
||||||
* ------------------------------------
|
* ------------------------------------
|
||||||
*/
|
*/
|
||||||
static sxi32 VmErrorFormat(ph7_vm *pVm, sxi32 iErr, const char *zFormat, ...) {
|
sxi32 VmErrorFormat(ph7_vm *pVm, sxi32 iErr, const char *zFormat, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
sxi32 rc;
|
sxi32 rc;
|
||||||
va_start(ap, zFormat);
|
va_start(ap, zFormat);
|
||||||
|
@ -4517,6 +4508,87 @@ static sxi32 VmByteCodeExec(
|
||||||
pc = nJump - 1;
|
pc = nJump - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* OP_CLASS_INIT P1 P2 P3
|
||||||
|
* Perform additional class initialization, by adding base classes
|
||||||
|
* and interfaces to its definition.
|
||||||
|
*/
|
||||||
|
case PH7_OP_CLASS_INIT:
|
||||||
|
{
|
||||||
|
ph7_class_info *pClassInfo = (ph7_class_info *)pInstr->p3;
|
||||||
|
ph7_class *pClass = PH7_VmExtractClass(pVm, pClassInfo->sName.zString, pClassInfo->sName.nByte, FALSE, 0);
|
||||||
|
ph7_class *pBase = 0;
|
||||||
|
if(pInstr->iP1) {
|
||||||
|
/* This class inherits from other classes */
|
||||||
|
SyString *apExtends;
|
||||||
|
while(SySetGetNextEntry(&pClassInfo->sExtends, (void **)&apExtends) == SXRET_OK) {
|
||||||
|
pBase = PH7_VmExtractClass(pVm, apExtends->zString, apExtends->nByte, FALSE, 0);
|
||||||
|
if(pBase == 0) {
|
||||||
|
/* Non-existent base class */
|
||||||
|
VmErrorFormat(&(*pVm), PH7_CTX_ERR, "Call to non-existent base class '%z'", &apExtends->zString);
|
||||||
|
} else if(pBase->iFlags & PH7_CLASS_INTERFACE) {
|
||||||
|
/* Trying to inherit from interface */
|
||||||
|
VmErrorFormat(&(*pVm), PH7_CTX_ERR, "Class '%z' cannot inherit from interface '%z'", &pClass->sName.zString, &apExtends->zString);
|
||||||
|
} else if(pBase->iFlags & PH7_CLASS_FINAL) {
|
||||||
|
/* Trying to inherit from final class */
|
||||||
|
VmErrorFormat(&(*pVm), PH7_CTX_ERR, "Class '%z' cannot inherit from final class '%z'", &pClass->sName.zString, &apExtends->zString);
|
||||||
|
}
|
||||||
|
rc = PH7_ClassInherit(pVm, pClass, pBase);
|
||||||
|
if(rc != SXRET_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(pInstr->iP2) {
|
||||||
|
/* This class implements some interfaces */
|
||||||
|
SyString *apImplements;
|
||||||
|
while(SySetGetNextEntry(&pClassInfo->sImplements, (void **)&apImplements) == SXRET_OK) {
|
||||||
|
pBase = PH7_VmExtractClass(pVm, apImplements->zString, apImplements->nByte, FALSE, 0);
|
||||||
|
if(pBase == 0) {
|
||||||
|
/* Non-existent interface */
|
||||||
|
VmErrorFormat(&(*pVm), PH7_CTX_ERR, "Call to non-existent interface '%z'", &apImplements->zString);
|
||||||
|
} else if((pBase->iFlags & PH7_CLASS_INTERFACE) == 0) {
|
||||||
|
/* Trying to implement a class */
|
||||||
|
VmErrorFormat(&(*pVm), PH7_CTX_ERR, "Class '%z' cannot implement a class '%z'", &pClass->sName.zString, &apImplements->zString);
|
||||||
|
}
|
||||||
|
rc = PH7_ClassImplement(pClass, pBase);
|
||||||
|
if(rc != SXRET_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* OP_INTERFACE_INIT P1 * P3
|
||||||
|
* Perform additional interface initialization, by adding base interfaces
|
||||||
|
* to its definition.
|
||||||
|
*/
|
||||||
|
case PH7_OP_INTERFACE_INIT:
|
||||||
|
{
|
||||||
|
ph7_class_info *pClassInfo = (ph7_class_info *)pInstr->p3;
|
||||||
|
ph7_class *pClass = PH7_VmExtractClass(pVm, pClassInfo->sName.zString, pClassInfo->sName.nByte, FALSE, 0);
|
||||||
|
ph7_class *pBase = 0;
|
||||||
|
if(pInstr->iP1) {
|
||||||
|
/* This interface inherits from other interface */
|
||||||
|
SyString *apExtends;
|
||||||
|
while(SySetGetNextEntry(&pClassInfo->sExtends, (void **)&apExtends) == SXRET_OK) {
|
||||||
|
pBase = PH7_VmExtractClass(pVm, apExtends->zString, apExtends->nByte, FALSE, 0);
|
||||||
|
if(pBase == 0) {
|
||||||
|
/* Non-existent base interface */
|
||||||
|
VmErrorFormat(&(*pVm), PH7_CTX_ERR, "Call to non-existent base interface '%z'", &apExtends->zString);
|
||||||
|
} else if((pBase->iFlags & PH7_CLASS_INTERFACE) == 0) {
|
||||||
|
/* Trying to inherit from class */
|
||||||
|
VmErrorFormat(&(*pVm), PH7_CTX_ERR, "Interface '%z' cannot inherit from class '%z'", &pClass->sName.zString, &apExtends->zString);
|
||||||
|
}
|
||||||
|
rc = PH7_ClassInterfaceInherit(pClass, pBase);
|
||||||
|
if(rc != SXRET_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* OP_FOREACH_INIT * P2 P3
|
* OP_FOREACH_INIT * P2 P3
|
||||||
* Prepare a foreach step.
|
* Prepare a foreach step.
|
||||||
|
@ -6034,6 +6106,12 @@ static const char *VmInstrToString(sxi32 nOp) {
|
||||||
case PH7_OP_THROW:
|
case PH7_OP_THROW:
|
||||||
zOp = "THROW ";
|
zOp = "THROW ";
|
||||||
break;
|
break;
|
||||||
|
case PH7_OP_CLASS_INIT:
|
||||||
|
zOp = "CLASS_INIT ";
|
||||||
|
break;
|
||||||
|
case PH7_OP_INTERFACE_INIT:
|
||||||
|
zOp = "INTER_INIT ";
|
||||||
|
break;
|
||||||
case PH7_OP_FOREACH_INIT:
|
case PH7_OP_FOREACH_INIT:
|
||||||
zOp = "4EACH_INIT ";
|
zOp = "4EACH_INIT ";
|
||||||
break;
|
break;
|
||||||
|
@ -6766,16 +6844,23 @@ static int vm_builtin_method_exists(ph7_context *pCtx, int nArg, ph7_value **apA
|
||||||
static int vm_builtin_class_exists(ph7_context *pCtx, int nArg, ph7_value **apArg) {
|
static int vm_builtin_class_exists(ph7_context *pCtx, int nArg, ph7_value **apArg) {
|
||||||
int res = 0; /* Assume class does not exists */
|
int res = 0; /* Assume class does not exists */
|
||||||
if(nArg > 0) {
|
if(nArg > 0) {
|
||||||
|
SyHashEntry *pEntry = 0;
|
||||||
const char *zName;
|
const char *zName;
|
||||||
int nLen;
|
int nLen;
|
||||||
/* Extract given name */
|
/* Extract given name */
|
||||||
zName = ph7_value_to_string(apArg[0], &nLen);
|
zName = ph7_value_to_string(apArg[0], &nLen);
|
||||||
/* Perform a hashlookup */
|
/* Perform a hashlookup */
|
||||||
if(nLen > 0 && SyHashGet(&pCtx->pVm->hClass, (const void *)zName, (sxu32)nLen) != 0) {
|
if(nLen > 0) {
|
||||||
|
pEntry = SyHashGet(&pCtx->pVm->hClass, (const void *)zName, (sxu32)nLen);
|
||||||
|
}
|
||||||
|
if(pEntry) {
|
||||||
|
ph7_class *pClass = (ph7_class *)pEntry->pUserData;
|
||||||
|
if((pClass->iFlags & PH7_CLASS_INTERFACE) == 0) {
|
||||||
/* class is available */
|
/* class is available */
|
||||||
res = 1;
|
res = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ph7_result_bool(pCtx, res);
|
ph7_result_bool(pCtx, res);
|
||||||
return PH7_OK;
|
return PH7_OK;
|
||||||
}
|
}
|
||||||
|
@ -6805,14 +6890,9 @@ static int vm_builtin_interface_exists(ph7_context *pCtx, int nArg, ph7_value **
|
||||||
}
|
}
|
||||||
if(pEntry) {
|
if(pEntry) {
|
||||||
ph7_class *pClass = (ph7_class *)pEntry->pUserData;
|
ph7_class *pClass = (ph7_class *)pEntry->pUserData;
|
||||||
while(pClass) {
|
|
||||||
if(pClass->iFlags & PH7_CLASS_INTERFACE) {
|
if(pClass->iFlags & PH7_CLASS_INTERFACE) {
|
||||||
/* interface is available */
|
/* interface is available */
|
||||||
res = 1;
|
res = 1;
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* Next with the same name */
|
|
||||||
pClass = pClass->pNextName;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11681,18 +11761,13 @@ PH7_PRIVATE ph7_class *PH7_VmExtractClass(
|
||||||
}
|
}
|
||||||
pClass = (ph7_class *)pEntry->pUserData;
|
pClass = (ph7_class *)pEntry->pUserData;
|
||||||
if(!iLoadable) {
|
if(!iLoadable) {
|
||||||
/* Return the first class seen */
|
/* Return the class absolutely */
|
||||||
return pClass;
|
return pClass;
|
||||||
} else {
|
} else {
|
||||||
/* Check the collision list */
|
|
||||||
while(pClass) {
|
|
||||||
if((pClass->iFlags & (PH7_CLASS_INTERFACE | PH7_CLASS_ABSTRACT)) == 0) {
|
if((pClass->iFlags & (PH7_CLASS_INTERFACE | PH7_CLASS_ABSTRACT)) == 0) {
|
||||||
/* Class is loadable */
|
/* Class is loadable */
|
||||||
return pClass;
|
return pClass;
|
||||||
}
|
}
|
||||||
/* Point to the next entry */
|
|
||||||
pClass = pClass->pNextName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/* No such loadable class */
|
/* No such loadable class */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -38,7 +38,9 @@ typedef struct ph7_foreach_info ph7_foreach_info;
|
||||||
typedef struct ph7_foreach_step ph7_foreach_step;
|
typedef struct ph7_foreach_step ph7_foreach_step;
|
||||||
typedef struct ph7_hashmap_node ph7_hashmap_node;
|
typedef struct ph7_hashmap_node ph7_hashmap_node;
|
||||||
typedef struct ph7_hashmap ph7_hashmap;
|
typedef struct ph7_hashmap ph7_hashmap;
|
||||||
|
typedef struct ph7_class_info ph7_class_info;
|
||||||
typedef struct ph7_class ph7_class;
|
typedef struct ph7_class ph7_class;
|
||||||
|
|
||||||
/* Symisc Standard types */
|
/* Symisc Standard types */
|
||||||
#if !defined(SYMISC_STD_TYPES)
|
#if !defined(SYMISC_STD_TYPES)
|
||||||
#define SYMISC_STD_TYPES
|
#define SYMISC_STD_TYPES
|
||||||
|
@ -1021,6 +1023,15 @@ struct ph7_builtin_constant {
|
||||||
/* Forward reference */
|
/* Forward reference */
|
||||||
typedef struct ph7_class_method ph7_class_method;
|
typedef struct ph7_class_method ph7_class_method;
|
||||||
typedef struct ph7_class_attr ph7_class_attr;
|
typedef struct ph7_class_attr ph7_class_attr;
|
||||||
|
/*
|
||||||
|
* Information about class/interface inheritance and interface implementation
|
||||||
|
* is stored in an instance of the following structure.
|
||||||
|
*/
|
||||||
|
struct ph7_class_info {
|
||||||
|
SyString sName; /* Class full qualified name */
|
||||||
|
SySet sExtends; /* List of inherited classes / interfaces */
|
||||||
|
SySet sImplements; /* List of implemented interfaces */
|
||||||
|
};
|
||||||
/*
|
/*
|
||||||
* Each class is parsed out and stored in an instance of the following structure.
|
* Each class is parsed out and stored in an instance of the following structure.
|
||||||
* PH7 introduced powerfull extensions to the PHP 5 OO subsystems.
|
* PH7 introduced powerfull extensions to the PHP 5 OO subsystems.
|
||||||
|
@ -1035,7 +1046,6 @@ struct ph7_class {
|
||||||
SyHash hMethod; /* Class methods */
|
SyHash hMethod; /* Class methods */
|
||||||
sxu32 nLine; /* Line number on which this class was declared */
|
sxu32 nLine; /* Line number on which this class was declared */
|
||||||
SySet aInterface; /* Implemented interface container */
|
SySet aInterface; /* Implemented interface container */
|
||||||
ph7_class *pNextName; /* Next class [interface, abstract, etc.] with the same name */
|
|
||||||
};
|
};
|
||||||
/* Class configuration flags */
|
/* Class configuration flags */
|
||||||
#define PH7_CLASS_FINAL 0x001 /* Class is final [cannot be extended] */
|
#define PH7_CLASS_FINAL 0x001 /* Class is final [cannot be extended] */
|
||||||
|
@ -1361,6 +1371,8 @@ enum ph7_vm_op {
|
||||||
PH7_OP_CVT_NULL, /* NULL cast */
|
PH7_OP_CVT_NULL, /* NULL cast */
|
||||||
PH7_OP_CVT_ARRAY, /* Array cast */
|
PH7_OP_CVT_ARRAY, /* Array cast */
|
||||||
PH7_OP_CVT_OBJ, /* Object cast */
|
PH7_OP_CVT_OBJ, /* Object cast */
|
||||||
|
PH7_OP_CLASS_INIT, /* Class init */
|
||||||
|
PH7_OP_INTERFACE_INIT,/* Interface init */
|
||||||
PH7_OP_FOREACH_INIT, /* For each init */
|
PH7_OP_FOREACH_INIT, /* For each init */
|
||||||
PH7_OP_FOREACH_STEP, /* For each step */
|
PH7_OP_FOREACH_STEP, /* For each step */
|
||||||
PH7_OP_IS_A, /* Instanceof */
|
PH7_OP_IS_A, /* Instanceof */
|
||||||
|
@ -1690,6 +1702,7 @@ PH7_PRIVATE sxi32 PH7_StripTagsFromString(ph7_context *pCtx, const char *zIn, in
|
||||||
PH7_PRIVATE sxi32 PH7_ParseIniString(ph7_context *pCtx, const char *zIn, sxu32 nByte, int bProcessSection);
|
PH7_PRIVATE sxi32 PH7_ParseIniString(ph7_context *pCtx, const char *zIn, sxu32 nByte, int bProcessSection);
|
||||||
#endif
|
#endif
|
||||||
/* oo.c function prototypes */
|
/* 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, sxu32 nLine);
|
PH7_PRIVATE ph7_class *PH7_NewRawClass(ph7_vm *pVm, const SyString *pName, sxu32 nLine);
|
||||||
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);
|
||||||
PH7_PRIVATE ph7_class_method *PH7_NewClassMethod(ph7_vm *pVm, ph7_class *pClass, const SyString *pName, sxu32 nLine,
|
PH7_PRIVATE ph7_class_method *PH7_NewClassMethod(ph7_vm *pVm, ph7_class *pClass, const SyString *pName, sxu32 nLine,
|
||||||
|
@ -1698,7 +1711,7 @@ PH7_PRIVATE ph7_class_method *PH7_ClassExtractMethod(ph7_class *pClass, const ch
|
||||||
PH7_PRIVATE ph7_class_attr *PH7_ClassExtractAttribute(ph7_class *pClass, const char *zName, sxu32 nByte);
|
PH7_PRIVATE ph7_class_attr *PH7_ClassExtractAttribute(ph7_class *pClass, const char *zName, sxu32 nByte);
|
||||||
PH7_PRIVATE sxi32 PH7_ClassInstallAttr(ph7_class *pClass, ph7_class_attr *pAttr);
|
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_ClassInstallMethod(ph7_class *pClass, ph7_class_method *pMeth);
|
||||||
PH7_PRIVATE sxi32 PH7_ClassInherit(ph7_gen_state *pGen, ph7_class *pSub, ph7_class *pBase);
|
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_ClassInterfaceInherit(ph7_class *pSub, ph7_class *pBase);
|
||||||
PH7_PRIVATE sxi32 PH7_ClassImplement(ph7_class *pMain, ph7_class *pInterface);
|
PH7_PRIVATE sxi32 PH7_ClassImplement(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_NewClassInstance(ph7_vm *pVm, ph7_class *pClass);
|
||||||
|
|
|
@ -152,6 +152,36 @@ int main(int argc, char **argv) {
|
||||||
Output_Consumer, /* Error log consumer */
|
Output_Consumer, /* Error log consumer */
|
||||||
0 /* NULL: Callback Private data */
|
0 /* NULL: Callback Private data */
|
||||||
);
|
);
|
||||||
|
/* Initialize the VM */
|
||||||
|
rc = ph7_vm_init(pEngine, &pVm);
|
||||||
|
if(rc != PH7_OK) {
|
||||||
|
if(rc == PH7_NOMEM) {
|
||||||
|
Fatal("Out of memory");
|
||||||
|
} else if(rc == PH7_VM_ERR) {
|
||||||
|
Fatal("VM initialization error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Now we have our VM initialized,it's time to configure our VM.
|
||||||
|
* We will install the VM output consumer callback defined above
|
||||||
|
* so that we can consume the VM output and redirect it to STDOUT.
|
||||||
|
*/
|
||||||
|
rc = ph7_vm_config(pVm,
|
||||||
|
PH7_VM_CONFIG_OUTPUT,
|
||||||
|
Output_Consumer, /* Output Consumer callback */
|
||||||
|
0 /* Callback private data */
|
||||||
|
);
|
||||||
|
if(rc != PH7_OK) {
|
||||||
|
Fatal("Error while installing the VM output consumer callback");
|
||||||
|
}
|
||||||
|
rc = ph7_vm_config(pVm, PH7_VM_CONFIG_ERR_REPORT, 1, 0);
|
||||||
|
if(rc != PH7_OK) {
|
||||||
|
Fatal("Error while configuring the VM error reporting");
|
||||||
|
}
|
||||||
|
if(err_report) {
|
||||||
|
/* Report script run-time errors */
|
||||||
|
ph7_vm_config(pVm, PH7_VM_CONFIG_ERR_REPORT);
|
||||||
|
}
|
||||||
/* Now,it's time to compile our PHP file */
|
/* Now,it's time to compile our PHP file */
|
||||||
rc = ph7_compile_file(
|
rc = ph7_compile_file(
|
||||||
pEngine, /* PH7 Engine */
|
pEngine, /* PH7 Engine */
|
||||||
|
@ -169,33 +199,12 @@ int main(int argc, char **argv) {
|
||||||
Fatal("Compile error");
|
Fatal("Compile error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* Now we have our script compiled,it's time to configure our VM.
|
|
||||||
* We will install the VM output consumer callback defined above
|
|
||||||
* so that we can consume the VM output and redirect it to STDOUT.
|
|
||||||
*/
|
|
||||||
rc = ph7_vm_config(pVm,
|
|
||||||
PH7_VM_CONFIG_OUTPUT,
|
|
||||||
Output_Consumer, /* Output Consumer callback */
|
|
||||||
0 /* Callback private data */
|
|
||||||
);
|
|
||||||
if(rc != PH7_OK) {
|
|
||||||
Fatal("Error while installing the VM output consumer callback");
|
|
||||||
}
|
|
||||||
rc = ph7_vm_config(pVm, PH7_VM_CONFIG_ERR_REPORT, 1, 0);
|
|
||||||
if(rc != PH7_OK) {
|
|
||||||
Fatal("Error while configuring the VM error reporting");
|
|
||||||
}
|
|
||||||
/* Register script agruments so we can access them later using the $argv[]
|
/* Register script agruments so we can access them later using the $argv[]
|
||||||
* array from the compiled PHP program.
|
* array from the compiled PHP program.
|
||||||
*/
|
*/
|
||||||
for(n = n + 1; n < argc ; ++n) {
|
for(n = n + 1; n < argc ; ++n) {
|
||||||
ph7_vm_config(pVm, PH7_VM_CONFIG_ARGV_ENTRY, argv[n]/* Argument value */);
|
ph7_vm_config(pVm, PH7_VM_CONFIG_ARGV_ENTRY, argv[n]/* Argument value */);
|
||||||
}
|
}
|
||||||
if(err_report) {
|
|
||||||
/* Report script run-time errors */
|
|
||||||
ph7_vm_config(pVm, PH7_VM_CONFIG_ERR_REPORT);
|
|
||||||
}
|
|
||||||
if(dump_vm) {
|
if(dump_vm) {
|
||||||
/* Dump PH7 byte-code instructions */
|
/* Dump PH7 byte-code instructions */
|
||||||
ph7_vm_dump_v2(pVm,
|
ph7_vm_dump_v2(pVm,
|
||||||
|
|
Loading…
Reference in New Issue