diff --git a/engine/compiler.c b/engine/compiler.c index 913c10e..b9b3e54 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -4006,12 +4006,27 @@ Synchronize: static sxi32 PH7_CompileClassInterface(ph7_gen_state *pGen) { sxu32 nLine = pGen->pIn->nLine; ph7_class *pClass, *pBase; + ph7_class_info *pClassInfo; SyToken *pEnd, *pTmp; SyString *pName; sxi32 nKwrd; sxi32 rc; + sxi32 iP1 = 0; /* Jump the 'interface' keyword */ 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 */ pName = &pGen->pIn->sData; /* 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"); 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 */ pClass->iFlags = PH7_CLASS_INTERFACE; /* Assume no base class is given */ pBase = 0; if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_KEYWORD)) { + SyString pBaseName; nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData); if(nKwrd == PH7_TKWRD_EXTENDS /* interface b extends a */) { - SyString *pBaseName; /* Extract base interface */ pGen->pIn++; - if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_ID) == 0) { - /* Syntax error */ - rc = PH7_GenCompileError(pGen, E_ERROR, nLine, - "Expected 'interface_name' after 'extends' keyword inside interface '%z'", - pName); - SyMemBackendPoolFree(&pGen->pVm->sAllocator, pClass); - if(rc == SXERR_ABORT) { - /* Error count limit reached,abort immediately */ - return SXERR_ABORT; + for(;;) { + if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_ID) == 0) { + /* Syntax error */ + rc = PH7_GenCompileError(pGen, E_ERROR, nLine, + "Expected 'interface_name' after 'extends' keyword inside interface '%z'", + pName); + SyMemBackendPoolFree(&pGen->pVm->sAllocator, pClass); + if(rc == SXERR_ABORT) { + /* Error count limit reached,abort immediately */ + return SXERR_ABORT; + } + return SXRET_OK; } - return SXRET_OK; - } - pBaseName = &pGen->pIn->sData; - pBase = PH7_VmExtractClass(pGen->pVm, pBaseName->zString, pBaseName->nByte, FALSE, 0); - /* Only interface is allowed */ - if(pBase == 0 || (pBase->iFlags & PH7_CLASS_INTERFACE) == 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; + /* Extract base class name */ + char *sName = SyMemBackendStrDup(&pGen->pVm->sAllocator, pGen->pIn->sData.zString, pGen->pIn->sData.nByte); + SyStringInitFromBuf(&pBaseName, sName, SyStrlen(sName)); + /* Register inherited class */ + SySetPut(&pClassInfo->sExtends, (const void *)&pBaseName); + /* Advance the stream cursor */ + pGen->pIn++; + if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_COMMA) == 0) { + break; } + /* Jump the comma operator */ + pGen->pIn++; } - /* Advance the stream cursor */ - pGen->pIn++; + iP1 = 1; } } 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 */ rc = PH7_VmInstallClass(pGen->pVm, pClass); - if(rc == SXRET_OK && pBase) { - /* Inherit from the base interface */ - rc = PH7_ClassInterfaceInherit(pClass, pBase); + if(iP1) { + /* Emit the INTERFACE_INIT instruction only if there is such a need */ + PH7_VmEmitInstr(pGen->pVm, PH7_OP_INTERFACE_INIT, iP1, 0, pClassInfo, 0); } if(rc != SXRET_OK) { PH7_GenCompileError(pGen, E_ERROR, nLine, "Fatal, PH7 is running out of memory"); diff --git a/engine/vm.c b/engine/vm.c index f3b1751..13ef129 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -4560,12 +4560,33 @@ static sxi32 VmByteCodeExec( break; } /* - * OP_INTERFACE_INIT * * P3 + * 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; } /*