Implement C3 class linearization and validate inheritance graphs
Build / AerScript (push) Successful in 2m13s
Build / AerScript (push) Successful in 2m13s
This commit is contained in:
+2
-3
@@ -3749,6 +3749,7 @@ static sxi32 PH7_GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) {
|
|||||||
if(pClassInfo == 0) {
|
if(pClassInfo == 0) {
|
||||||
PH7_GenCompileError(pGen, E_ERROR, nLine, "PH7 is running out-of-memory");
|
PH7_GenCompileError(pGen, E_ERROR, nLine, "PH7 is running out-of-memory");
|
||||||
}
|
}
|
||||||
|
pClass->pInfo = pClassInfo;
|
||||||
/* Assume a standalone class */
|
/* Assume a standalone class */
|
||||||
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;
|
||||||
@@ -3987,10 +3988,8 @@ static sxi32 PH7_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(iP1 || iP2) {
|
/* Root classes also need their singleton MRO initialized. */
|
||||||
/* Emit the CLASS_INIT instruction only if there is such a need */
|
|
||||||
PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_CLASS_INIT, iP1, iP2, pClassInfo, 0);
|
PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_CLASS_INIT, iP1, iP2, pClassInfo, 0);
|
||||||
}
|
|
||||||
if(rc != SXRET_OK) {
|
if(rc != SXRET_OK) {
|
||||||
PH7_GenCompileError(pGen, E_ERROR, nLine, "PH7 is running out-of-memory");
|
PH7_GenCompileError(pGen, E_ERROR, nLine, "PH7 is running out-of-memory");
|
||||||
}
|
}
|
||||||
|
|||||||
+129
@@ -60,6 +60,8 @@ PH7_PRIVATE ph7_class *PH7_NewRawClass(ph7_vm *pVm, const SyString *pName) {
|
|||||||
SyHashInit(&pClass->hAttr, &pVm->sAllocator, 0, 0);
|
SyHashInit(&pClass->hAttr, &pVm->sAllocator, 0, 0);
|
||||||
SyHashInit(&pClass->hDerived, &pVm->sAllocator, 0, 0);
|
SyHashInit(&pClass->hDerived, &pVm->sAllocator, 0, 0);
|
||||||
SySetInit(&pClass->aInterface, &pVm->sAllocator, sizeof(ph7_class *));
|
SySetInit(&pClass->aInterface, &pVm->sAllocator, sizeof(ph7_class *));
|
||||||
|
SySetInit(&pClass->aBase, &pVm->sAllocator, sizeof(ph7_class *));
|
||||||
|
SySetInit(&pClass->aMro, &pVm->sAllocator, sizeof(ph7_class *));
|
||||||
/* All done */
|
/* All done */
|
||||||
return pClass;
|
return pClass;
|
||||||
}
|
}
|
||||||
@@ -201,6 +203,133 @@ PH7_PRIVATE sxi32 PH7_ClassInstallMethod(ph7_class *pClass, ph7_class_method *pM
|
|||||||
rc = SyHashInsert(&pClass->hMethod, (const void *)pName->zString, pName->nByte, pMeth);
|
rc = SyHashInsert(&pClass->hMethod, (const void *)pName->zString, pName->nByte, pMeth);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* Build [C] + merge(MRO(B1), ..., MRO(Bn), [B1, ..., Bn]).
|
||||||
|
* Resolve declarations rather than hDerived: bytecode initialization may not
|
||||||
|
* have reached a forward-declared base yet. Merge cursors are private so that
|
||||||
|
* neither shared ancestors nor an autoloader can change a base's MRO.
|
||||||
|
*/
|
||||||
|
PH7_PRIVATE sxi32 PH7_ClassBuildMro(ph7_vm *pVm, ph7_class *pClass) {
|
||||||
|
SySet sBase, sMro;
|
||||||
|
ph7_class *pBase, *pCandidate;
|
||||||
|
SySet *pSeq;
|
||||||
|
sxu32 *aPos = 0;
|
||||||
|
sxu32 i, j, k, nBase, nSeq;
|
||||||
|
sxi32 rc = SXRET_OK;
|
||||||
|
int bPending, bInTail;
|
||||||
|
if(pClass->iFlags & PH7_CLASS_INTERFACE) {
|
||||||
|
return SXRET_OK;
|
||||||
|
}
|
||||||
|
if(pClass->iMroState == 2) {
|
||||||
|
return SXRET_OK;
|
||||||
|
}
|
||||||
|
if(pClass->iMroState == 1) {
|
||||||
|
PH7_VmThrowError(pVm, PH7_CTX_ERR, "Inheritance cycle involving class '%z'", &pClass->sName);
|
||||||
|
return SXERR_INVALID;
|
||||||
|
}
|
||||||
|
/* Set before resolution, which can reenter through an autoloader. */
|
||||||
|
pClass->iMroState = 1;
|
||||||
|
SySetInit(&sBase, &pVm->sAllocator, sizeof(ph7_class *));
|
||||||
|
SySetInit(&sMro, &pVm->sAllocator, sizeof(ph7_class *));
|
||||||
|
if(pClass->pInfo) {
|
||||||
|
for(i = 0; i < SySetUsed(&pClass->pInfo->sExtends); i++) {
|
||||||
|
SyString *pName = (SyString *)SySetAt(&pClass->pInfo->sExtends, i);
|
||||||
|
pBase = PH7_VmExtractClass(pVm, pName->zString, pName->nByte, FALSE);
|
||||||
|
if(pBase == 0) {
|
||||||
|
PH7_VmThrowError(pVm, PH7_CTX_ERR, "Call to non-existent base class '%z'", pName);
|
||||||
|
} else if(pBase == pClass) {
|
||||||
|
PH7_VmThrowError(pVm, PH7_CTX_ERR, "Class '%z' cannot inherit from itself", &pClass->sName);
|
||||||
|
} else if(pBase->iFlags & PH7_CLASS_INTERFACE) {
|
||||||
|
PH7_VmThrowError(pVm, PH7_CTX_ERR, "Class '%z' cannot inherit from interface '%z'", &pClass->sName, pName);
|
||||||
|
} else if(pBase->iFlags & PH7_CLASS_FINAL) {
|
||||||
|
PH7_VmThrowError(pVm, PH7_CTX_ERR, "Class '%z' cannot inherit from final class '%z'", &pClass->sName, pName);
|
||||||
|
}
|
||||||
|
for(j = 0; j < SySetUsed(&sBase); j++) {
|
||||||
|
if(*(ph7_class **)SySetAt(&sBase, j) == pBase) {
|
||||||
|
PH7_VmThrowError(pVm, PH7_CTX_ERR, "Duplicate base class '%z' in class '%z'", &pBase->sName, &pClass->sName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rc = SySetPut(&sBase, &pBase);
|
||||||
|
if(rc != SXRET_OK) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
rc = PH7_ClassBuildMro(pVm, pBase);
|
||||||
|
if(rc != SXRET_OK) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nBase = SySetUsed(&sBase);
|
||||||
|
nSeq = nBase + 1;
|
||||||
|
aPos = (sxu32 *)SyMemBackendAlloc(&pVm->sAllocator, nSeq * sizeof(sxu32));
|
||||||
|
if(aPos == 0) {
|
||||||
|
rc = SXERR_MEM;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
SyZero(aPos, nSeq * sizeof(sxu32));
|
||||||
|
rc = SySetPut(&sMro, &pClass);
|
||||||
|
if(rc != SXRET_OK) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
for(;;) {
|
||||||
|
bPending = FALSE;
|
||||||
|
pCandidate = 0;
|
||||||
|
for(i = 0; i < nSeq; i++) {
|
||||||
|
pSeq = i == nBase ? &sBase : &(*(ph7_class **)SySetAt(&sBase, i))->aMro;
|
||||||
|
if(aPos[i] >= SySetUsed(pSeq)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bPending = TRUE;
|
||||||
|
pCandidate = *(ph7_class **)SySetAt(pSeq, aPos[i]);
|
||||||
|
bInTail = FALSE;
|
||||||
|
for(j = 0; j < nSeq && !bInTail; j++) {
|
||||||
|
pSeq = j == nBase ? &sBase : &(*(ph7_class **)SySetAt(&sBase, j))->aMro;
|
||||||
|
for(k = aPos[j] + 1; k < SySetUsed(pSeq); k++) {
|
||||||
|
if(*(ph7_class **)SySetAt(pSeq, k) == pCandidate) {
|
||||||
|
bInTail = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!bInTail) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pCandidate = 0;
|
||||||
|
}
|
||||||
|
if(!bPending) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(pCandidate == 0) {
|
||||||
|
PH7_VmThrowError(pVm, PH7_CTX_ERR, "Inconsistent C3 hierarchy for class '%z'", &pClass->sName);
|
||||||
|
rc = SXERR_INVALID;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
rc = SySetPut(&sMro, &pCandidate);
|
||||||
|
if(rc != SXRET_OK) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
for(i = 0; i < nSeq; i++) {
|
||||||
|
pSeq = i == nBase ? &sBase : &(*(ph7_class **)SySetAt(&sBase, i))->aMro;
|
||||||
|
if(aPos[i] < SySetUsed(pSeq) && *(ph7_class **)SySetAt(pSeq, aPos[i]) == pCandidate) {
|
||||||
|
aPos[i]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Publish only a complete linearization. */
|
||||||
|
SySetRelease(&pClass->aBase);
|
||||||
|
SySetRelease(&pClass->aMro);
|
||||||
|
pClass->aBase = sBase;
|
||||||
|
pClass->aMro = sMro;
|
||||||
|
pClass->iMroState = 2;
|
||||||
|
done:
|
||||||
|
SyMemBackendFree(&pVm->sAllocator, aPos);
|
||||||
|
if(rc != SXRET_OK) {
|
||||||
|
SySetRelease(&sBase);
|
||||||
|
SySetRelease(&sMro);
|
||||||
|
pClass->iMroState = 0;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Perform an inheritance operation.
|
* Perform an inheritance operation.
|
||||||
* According to the PHP language reference manual
|
* According to the PHP language reference manual
|
||||||
|
|||||||
+35
-26
@@ -451,7 +451,7 @@ static void VmLeaveFrame(ph7_vm *pVm) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Forward declaration */
|
/* Forward declaration */
|
||||||
static int VmInstanceOf(ph7_class *pThis, ph7_class *pClass);
|
static int VmInstanceOf(ph7_vm *pVm, ph7_class *pThis, ph7_class *pClass);
|
||||||
/*
|
/*
|
||||||
* Ranks for general parameter types. Class and interface specificity uses
|
* Ranks for general parameter types. Class and interface specificity uses
|
||||||
* the shortest inheritance distance instead, which is always lower than
|
* the shortest inheritance distance instead, which is always lower than
|
||||||
@@ -2577,7 +2577,7 @@ static sxi32 VmByteCodeExec(
|
|||||||
}
|
}
|
||||||
if(pThis) {
|
if(pThis) {
|
||||||
/* Perform the query */
|
/* Perform the query */
|
||||||
iRes = VmInstanceOf(pThis->pClass, pClass);
|
iRes = VmInstanceOf(pVm, pThis->pClass, pClass);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rc = PH7_MemObjCmp(pNos, pTos, FALSE, 0);
|
rc = PH7_MemObjCmp(pNos, pTos, FALSE, 0);
|
||||||
@@ -4195,7 +4195,7 @@ static sxi32 VmByteCodeExec(
|
|||||||
/* Make sure the loaded object is an instance of the 'Exception' base class.
|
/* Make sure the loaded object is an instance of the 'Exception' base class.
|
||||||
*/
|
*/
|
||||||
pException = PH7_VmExtractClass(&(*pVm), "Exception", sizeof("Exception") - 1, TRUE);
|
pException = PH7_VmExtractClass(&(*pVm), "Exception", sizeof("Exception") - 1, TRUE);
|
||||||
if(pException == 0 || !VmInstanceOf(pThis->pClass, pException)) {
|
if(pException == 0 || !VmInstanceOf(pVm, pThis->pClass, pException)) {
|
||||||
/* Exceptions must be valid objects derived from the Exception base class */
|
/* Exceptions must be valid objects derived from the Exception base class */
|
||||||
rc = VmUncaughtException(&(*pVm), pThis);
|
rc = VmUncaughtException(&(*pVm), pThis);
|
||||||
if(rc == SXERR_ABORT) {
|
if(rc == SXERR_ABORT) {
|
||||||
@@ -4307,21 +4307,15 @@ static sxi32 VmByteCodeExec(
|
|||||||
ph7_class_info *pClassInfo = (ph7_class_info *)pInstr->p3;
|
ph7_class_info *pClassInfo = (ph7_class_info *)pInstr->p3;
|
||||||
ph7_class *pClass = PH7_VmExtractClass(pVm, pClassInfo->sName.zString, pClassInfo->sName.nByte, FALSE);
|
ph7_class *pClass = PH7_VmExtractClass(pVm, pClassInfo->sName.zString, pClassInfo->sName.nByte, FALSE);
|
||||||
ph7_class *pBase = 0;
|
ph7_class *pBase = 0;
|
||||||
|
rc = PH7_ClassBuildMro(pVm, pClass);
|
||||||
|
if(rc != SXRET_OK) {
|
||||||
|
goto Abort;
|
||||||
|
}
|
||||||
if(pInstr->iP1) {
|
if(pInstr->iP1) {
|
||||||
/* This class inherits from other classes */
|
/* This class inherits from other classes */
|
||||||
SyString *apExtends;
|
sxu32 i;
|
||||||
while(SySetGetNextEntry(&pClassInfo->sExtends, (void **)&apExtends) == SXRET_OK) {
|
for(i = 0; i < SySetUsed(&pClass->aBase); i++) {
|
||||||
pBase = PH7_VmExtractClass(pVm, apExtends->zString, apExtends->nByte, FALSE);
|
pBase = *(ph7_class **)SySetAt(&pClass->aBase, i);
|
||||||
if(pBase == 0) {
|
|
||||||
/* Non-existent base class */
|
|
||||||
PH7_VmThrowError(&(*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 */
|
|
||||||
PH7_VmThrowError(&(*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 */
|
|
||||||
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Class '%z' cannot inherit from final class '%z'", &pClass->sName.zString, &apExtends->zString);
|
|
||||||
}
|
|
||||||
rc = PH7_ClassInherit(pVm, pClass, pBase);
|
rc = PH7_ClassInherit(pVm, pClass, pBase);
|
||||||
if(rc != SXRET_OK) {
|
if(rc != SXRET_OK) {
|
||||||
break;
|
break;
|
||||||
@@ -4495,7 +4489,7 @@ static sxi32 VmByteCodeExec(
|
|||||||
if(sName.nByte > 0) {
|
if(sName.nByte > 0) {
|
||||||
/* Extract the target method */
|
/* Extract the target method */
|
||||||
if(pNos->iFlags != MEMOBJ_PARENTOBJ) {
|
if(pNos->iFlags != MEMOBJ_PARENTOBJ) {
|
||||||
if(pScope && VmInstanceOf(pClass, pScope)) {
|
if(pScope && VmInstanceOf(pVm, pClass, pScope)) {
|
||||||
pMeth = PH7_ClassExtractMethod(pScope, sName.zString, sName.nByte);
|
pMeth = PH7_ClassExtractMethod(pScope, sName.zString, sName.nByte);
|
||||||
if(pMeth && (pMeth->iProtection != PH7_CLASS_PROT_PRIVATE || pMeth->sFunc.pClass != pScope)) {
|
if(pMeth && (pMeth->iProtection != PH7_CLASS_PROT_PRIVATE || pMeth->sFunc.pClass != pScope)) {
|
||||||
pMeth = 0;
|
pMeth = 0;
|
||||||
@@ -4544,7 +4538,7 @@ static sxi32 VmByteCodeExec(
|
|||||||
/* Extract the target attribute */
|
/* Extract the target attribute */
|
||||||
if(pNos->iFlags != MEMOBJ_PARENTOBJ) {
|
if(pNos->iFlags != MEMOBJ_PARENTOBJ) {
|
||||||
/* Private fields belong to their declaring class, even on a derived object. */
|
/* Private fields belong to their declaring class, even on a derived object. */
|
||||||
if(pScope && VmInstanceOf(pClass, pScope)) {
|
if(pScope && VmInstanceOf(pVm, pClass, pScope)) {
|
||||||
pAttr = PH7_ClassExtractAttribute(pScope, sName.zString, sName.nByte);
|
pAttr = PH7_ClassExtractAttribute(pScope, sName.zString, sName.nByte);
|
||||||
if(pAttr && pAttr->iProtection != PH7_CLASS_PROT_PRIVATE) {
|
if(pAttr && pAttr->iProtection != PH7_CLASS_PROT_PRIVATE) {
|
||||||
pAttr = 0;
|
pAttr = 0;
|
||||||
@@ -5092,7 +5086,7 @@ static sxi32 VmByteCodeExec(
|
|||||||
} else {
|
} else {
|
||||||
ph7_class_instance *pThis = (ph7_class_instance *)pArg->x.pOther;
|
ph7_class_instance *pThis = (ph7_class_instance *)pArg->x.pOther;
|
||||||
/* Make sure the object is an instance of the given class */
|
/* Make sure the object is an instance of the given class */
|
||||||
if(pThis == 0 || !VmInstanceOf(pThis->pClass, pClass)) {
|
if(pThis == 0 || !VmInstanceOf(pVm, pThis->pClass, pClass)) {
|
||||||
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR,
|
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR,
|
||||||
"Argument %u passed to function '%z()' must be an object of type '%z'",
|
"Argument %u passed to function '%z()' must be an object of type '%z'",
|
||||||
n+1, &pVmFunc->sName, pName);
|
n+1, &pVmFunc->sName, pName);
|
||||||
@@ -5207,7 +5201,7 @@ static sxi32 VmByteCodeExec(
|
|||||||
} else {
|
} else {
|
||||||
ph7_class_instance *pThis = (ph7_class_instance *)pObj->x.pOther;
|
ph7_class_instance *pThis = (ph7_class_instance *)pObj->x.pOther;
|
||||||
/* Make sure the object is an instance of the given class */
|
/* Make sure the object is an instance of the given class */
|
||||||
if(pThis == 0 || !VmInstanceOf(pThis->pClass, pClass)) {
|
if(pThis == 0 || !VmInstanceOf(pVm, pThis->pClass, pClass)) {
|
||||||
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR,
|
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR,
|
||||||
"Default value for argument %u of '%z()' must be an object of type '%z'",
|
"Default value for argument %u of '%z()' must be an object of type '%z'",
|
||||||
n+1, &pVmFunc->sName, pName);
|
n+1, &pVmFunc->sName, pName);
|
||||||
@@ -6258,7 +6252,7 @@ static int VmClassMemberAccess(
|
|||||||
} else {
|
} else {
|
||||||
/* Protected */
|
/* Protected */
|
||||||
/* Must be a derived class */
|
/* Must be a derived class */
|
||||||
if(!VmInstanceOf(pScope, pClass)) {
|
if(!VmInstanceOf(pVm, pScope, pClass)) {
|
||||||
return 0; /* Access is forbidden */
|
return 0; /* Access is forbidden */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6428,7 +6422,7 @@ static int VmQueryInterfaceSet(ph7_class *pClass, SySet *pSet) {
|
|||||||
* is an instance of the main class (second argument).
|
* is an instance of the main class (second argument).
|
||||||
* Otherwise FALSE is returned.
|
* Otherwise FALSE is returned.
|
||||||
*/
|
*/
|
||||||
static int VmInstanceOf(ph7_class *pThis, ph7_class *pClass) {
|
static int VmInstanceOf(ph7_vm *pVm, ph7_class *pThis, ph7_class *pClass) {
|
||||||
SyHashEntry *pEntry;
|
SyHashEntry *pEntry;
|
||||||
ph7_class *pDerived, *pParent;
|
ph7_class *pDerived, *pParent;
|
||||||
sxi32 rc;
|
sxi32 rc;
|
||||||
@@ -6436,6 +6430,18 @@ static int VmInstanceOf(ph7_class *pThis, ph7_class *pClass) {
|
|||||||
/* Instance of the same class */
|
/* Instance of the same class */
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
if(!(pThis->iFlags & PH7_CLASS_INTERFACE) && !(pClass->iFlags & PH7_CLASS_INTERFACE)) {
|
||||||
|
sxu32 i;
|
||||||
|
if(PH7_ClassBuildMro(pVm, pThis) != SXRET_OK) {
|
||||||
|
PH7_VmThrowError(pVm, PH7_CTX_ERR, "PH7 is running out-of-memory");
|
||||||
|
}
|
||||||
|
for(i = 1; i < SySetUsed(&pThis->aMro); i++) {
|
||||||
|
if(*(ph7_class **)SySetAt(&pThis->aMro, i) == pClass) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
/* Check implemented interfaces */
|
/* Check implemented interfaces */
|
||||||
rc = VmQueryInterfaceSet(pClass, &pThis->aInterface);
|
rc = VmQueryInterfaceSet(pClass, &pThis->aInterface);
|
||||||
if(rc) {
|
if(rc) {
|
||||||
@@ -6478,11 +6484,14 @@ static int VmInstanceOf(ph7_class *pThis, ph7_class *pClass) {
|
|||||||
* is a subclass of the main class (second argument).
|
* is a subclass of the main class (second argument).
|
||||||
* Otherwise FALSE is returned.
|
* Otherwise FALSE is returned.
|
||||||
*/
|
*/
|
||||||
static int VmSubclassOf(ph7_class *pClass, ph7_class *pBase) {
|
static int VmSubclassOf(ph7_vm *pVm, ph7_class *pClass, ph7_class *pBase) {
|
||||||
SySet *pInterface = &pClass->aInterface;
|
SySet *pInterface = &pClass->aInterface;
|
||||||
SyHashEntry *pEntry;
|
SyHashEntry *pEntry;
|
||||||
SyString *pName;
|
SyString *pName;
|
||||||
sxi32 rc;
|
sxi32 rc;
|
||||||
|
if(!(pClass->iFlags & PH7_CLASS_INTERFACE) && !(pBase->iFlags & PH7_CLASS_INTERFACE)) {
|
||||||
|
return pClass != pBase && VmInstanceOf(pVm, pClass, pBase);
|
||||||
|
}
|
||||||
while(pClass) {
|
while(pClass) {
|
||||||
pName = &pClass->sName;
|
pName = &pClass->sName;
|
||||||
/* Query the derived hashtable */
|
/* Query the derived hashtable */
|
||||||
@@ -6520,7 +6529,7 @@ static int vm_builtin_is_a(ph7_context *pCtx, int nArg, ph7_value **apArg) {
|
|||||||
pClass = VmExtractClassFromValue(pCtx->pVm, apArg[1]);
|
pClass = VmExtractClassFromValue(pCtx->pVm, apArg[1]);
|
||||||
if(pClass) {
|
if(pClass) {
|
||||||
/* Perform the query */
|
/* Perform the query */
|
||||||
res = VmInstanceOf(pThis->pClass, pClass);
|
res = VmInstanceOf(pCtx->pVm, pThis->pClass, pClass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Query result */
|
/* Query result */
|
||||||
@@ -6548,7 +6557,7 @@ static int vm_builtin_is_subclass_of(ph7_context *pCtx, int nArg, ph7_value **ap
|
|||||||
pMain = VmExtractClassFromValue(pCtx->pVm, apArg[1]);
|
pMain = VmExtractClassFromValue(pCtx->pVm, apArg[1]);
|
||||||
if(pClass && pMain) {
|
if(pClass && pMain) {
|
||||||
/* Perform the query */
|
/* Perform the query */
|
||||||
res = VmSubclassOf(pClass, pMain);
|
res = VmSubclassOf(pCtx->pVm, pClass, pMain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Query result */
|
/* Query result */
|
||||||
@@ -8288,7 +8297,7 @@ static sxi32 VmThrowException(
|
|||||||
/* No such class */
|
/* No such class */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(VmInstanceOf(pThis->pClass, pClass)) {
|
if(VmInstanceOf(pVm, pThis->pClass, pClass)) {
|
||||||
/* Catch block found,break immediately */
|
/* Catch block found,break immediately */
|
||||||
pCatch = &aCatch[j];
|
pCatch = &aCatch[j];
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1043,6 +1043,10 @@ struct ph7_class {
|
|||||||
SyHash hAttr; /* Class attributes [i.e: variables and constants] */
|
SyHash hAttr; /* Class attributes [i.e: variables and constants] */
|
||||||
SyHash hMethod; /* Class methods */
|
SyHash hMethod; /* Class methods */
|
||||||
SySet aInterface; /* Implemented interface container */
|
SySet aInterface; /* Implemented interface container */
|
||||||
|
ph7_class_info *pInfo; /* Declaration used to resolve forward bases */
|
||||||
|
SySet aBase; /* Direct class bases in extends order */
|
||||||
|
SySet aMro; /* C3 linearization, including this class first */
|
||||||
|
sxi32 iMroState; /* 0: unbuilt, 1: building, 2: ready */
|
||||||
};
|
};
|
||||||
/* 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] */
|
||||||
@@ -1766,6 +1770,7 @@ PH7_PRIVATE ph7_class_attr *PH7_ClassExtractAttribute(ph7_class *pClass, cons
|
|||||||
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_vm *pVm, ph7_class *pSub, ph7_class *pBase);
|
PH7_PRIVATE sxi32 PH7_ClassInherit(ph7_vm *pVm, ph7_class *pSub, ph7_class *pBase);
|
||||||
|
PH7_PRIVATE sxi32 PH7_ClassBuildMro(ph7_vm *pVm, ph7_class *pClass);
|
||||||
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_vm *pVm, ph7_class *pMain, ph7_class *pInterface);
|
PH7_PRIVATE sxi32 PH7_ClassImplement(ph7_vm *pVm, ph7_class *pMain, ph7_class *pInterface);
|
||||||
PH7_PRIVATE ph7_class_instance *PH7_NewClassInstance(ph7_vm *pVm, ph7_class *pClass);
|
PH7_PRIVATE ph7_class_instance *PH7_NewClassInstance(ph7_vm *pVm, ph7_class *pClass);
|
||||||
|
|||||||
Reference in New Issue
Block a user