Implement a fix also for interface. This commit also adds initial and partial support for multiple inheritance.

This commit is contained in:
Rafal Kupiec 2018-07-27 23:28:34 +02:00
parent a6a43b5f3b
commit bdf053a205
Signed by: belliash
GPG Key ID: 4E829243E0CFE6B4
2 changed files with 71 additions and 27 deletions

View File

@ -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,41 +4037,49 @@ 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++;
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_ID) == 0) { for(;;) {
/* Syntax error */ if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_ID) == 0) {
rc = PH7_GenCompileError(pGen, E_ERROR, nLine, /* Syntax error */
"Expected 'interface_name' after 'extends' keyword inside interface '%z'", rc = PH7_GenCompileError(pGen, E_ERROR, nLine,
pName); "Expected 'interface_name' after 'extends' keyword inside interface '%z'",
SyMemBackendPoolFree(&pGen->pVm->sAllocator, pClass); pName);
if(rc == SXERR_ABORT) { SyMemBackendPoolFree(&pGen->pVm->sAllocator, pClass);
/* Error count limit reached,abort immediately */ if(rc == SXERR_ABORT) {
return SXERR_ABORT; /* Error count limit reached,abort immediately */
return SXERR_ABORT;
}
return SXRET_OK;
} }
return SXRET_OK; /* Extract base class name */
} char *sName = SyMemBackendStrDup(&pGen->pVm->sAllocator, pGen->pIn->sData.zString, pGen->pIn->sData.nByte);
pBaseName = &pGen->pIn->sData; SyStringInitFromBuf(&pBaseName, sName, SyStrlen(sName));
pBase = PH7_VmExtractClass(pGen->pVm, pBaseName->zString, pBaseName->nByte, FALSE, 0); /* Register inherited class */
/* Only interface is allowed */ SySetPut(&pClassInfo->sExtends, (const void *)&pBaseName);
if(pBase == 0 || (pBase->iFlags & PH7_CLASS_INTERFACE) == 0) { /* Advance the stream cursor */
/* Inexistant interface */ pGen->pIn++;
rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, "Inexistant base interface '%z'", pBaseName); if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_COMMA) == 0) {
if(rc == SXERR_ABORT) { break;
/* Error count limit reached,abort immediately */
return SXERR_ABORT;
} }
/* Jump the comma operator */
pGen->pIn++;
} }
/* Advance the stream cursor */ iP1 = 1;
pGen->pIn++;
} }
} }
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_OCB /*'{'*/) == 0) { if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_OCB /*'{'*/) == 0) {
@ -4188,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");

View File

@ -4560,12 +4560,33 @@ static sxi32 VmByteCodeExec(
break; break;
} }
/* /*
* OP_INTERFACE_INIT * * P3 * OP_INTERFACE_INIT P1 * P3
* Perform additional interface initialization, by adding base interfaces * Perform additional interface initialization, by adding base interfaces
* to its definition. * to its definition.
*/ */
case PH7_OP_INTERFACE_INIT: 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; break;
} }
/* /*