diff --git a/engine/compiler.c b/engine/compiler.c index ef32d5d..84db7f3 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -4226,6 +4226,8 @@ static sxi32 GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) { SyString *pName; sxi32 nKwrd; sxi32 rc; + sxi32 iP1 = 0; + sxu32 iP2 = 0; /* Jump the 'class' keyword */ pGen->pIn++; if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_ID) == 0) { @@ -4256,50 +4258,42 @@ static sxi32 GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) { /* Assume a standalone class */ pBase = 0; if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_KEYWORD)) { - SyString *pBaseName; + SyString pBaseName; nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData); if(nKwrd == PH7_TKWRD_EXTENDS /* class b extends a */) { pGen->pIn++; /* Advance the stream cursor */ - if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_ID) == 0) { - /* Syntax error */ - rc = PH7_GenCompileError(pGen, E_ERROR, nLine, - "Expected 'class_name' after 'extends' keyword inside class '%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 'class_name' after 'extends' keyword inside class '%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; + /* Extract base class name */ + char *pName = malloc(pGen->pIn->sData.nByte); + SyStrncpy(pName, pGen->pIn->sData.zString, pGen->pIn->sData.nByte); + SyStringInitFromBuf(&pBaseName, pName, SyStrlen(pName)); + /* Register inherited class */ + SySetPut(&pClass->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++; } - /* Extract base class name */ - pBaseName = &pGen->pIn->sData; -// /* Perform the query */ -// pBase = PH7_VmExtractClass(pGen->pVm, pBaseName->zString, pBaseName->nByte, FALSE, 0); -// /* Interface is not allowed */ -// if(pBase == 0 || (pBase->iFlags & PH7_CLASS_INTERFACE)) { -// /* 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 */ - 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) { ph7_class *pInterface; - SyString *pIntName; + SyString pIntName; /* Interface implementation */ pGen->pIn++; /* Advance the stream cursor */ for(;;) { @@ -4308,35 +4302,28 @@ static sxi32 GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) { rc = PH7_GenCompileError(pGen, E_ERROR, nLine, "Expected 'interface_name' after 'implements' keyword inside class '%z' declaration", pName); + SyMemBackendPoolFree(&pGen->pVm->sAllocator, pClass); if(rc == SXERR_ABORT) { /* Error count limit reached,abort immediately */ return SXERR_ABORT; } - break; + return SXRET_OK; } /* Extract interface name */ - pIntName = &pGen->pIn->sData; - /* Make sure the interface is already defined */ - pInterface = PH7_VmExtractClass(pGen->pVm, pIntName->zString, pIntName->nByte, FALSE, 0); - /* Only interfaces are allowed */ - if(pInterface == 0 || (pInterface->iFlags & PH7_CLASS_INTERFACE) == 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); - } + char *pName = malloc(pGen->pIn->sData.nByte); + SyStrncpy(pName, pGen->pIn->sData.zString, pGen->pIn->sData.nByte); + SyStringInitFromBuf(&pIntName, pName, SyStrlen(pName)); + /* Register inherited class */ + SySetPut(&pClass->sImplements, (const void *)&pIntName); /* Advance the stream cursor */ pGen->pIn++; if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_COMMA) == 0) { 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) { @@ -4576,23 +4563,10 @@ static sxi32 GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) { } /* Install the class */ rc = PH7_VmInstallClass(pGen->pVm, pClass); -// if(rc == SXRET_OK) { -// ph7_class **apInterface; -// sxu32 n; -// 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(iP1 || iP2) { + /* Emit the CLASS_INIT instruction only if there is such a need */ + PH7_VmEmitInstr(pGen->pVm, PH7_OP_CLASS_INIT, iP1, iP2, pClass, 0); + } if(rc != SXRET_OK) { PH7_GenCompileError(pGen, E_ERROR, nLine, "Fatal, PH7 is running out of memory"); return SXERR_ABORT; diff --git a/engine/oop.c b/engine/oop.c index 33ca357..33c947b 100644 --- a/engine/oop.c +++ b/engine/oop.c @@ -41,6 +41,8 @@ PH7_PRIVATE ph7_class *PH7_NewRawClass(ph7_vm *pVm, const SyString *pName, sxu32 SyHashInit(&pClass->hAttr, &pVm->sAllocator, 0, 0); SyHashInit(&pClass->hDerived, &pVm->sAllocator, 0, 0); SySetInit(&pClass->aInterface, &pVm->sAllocator, sizeof(ph7_class *)); + SySetInit(&pClass->sExtends, &pVm->sAllocator, sizeof(SyString)); + SySetInit(&pClass->sImplements, &pVm->sAllocator, sizeof(SyString)); pClass->nLine = nLine; /* All done */ return pClass; diff --git a/engine/vm.c b/engine/vm.c index 47c4e95..cf3bc8a 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -4508,6 +4508,41 @@ static sxi32 VmByteCodeExec( pc = nJump - 1; 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 *pClass = (ph7_class *)pInstr->p3; + printf("Called by class: '%s'\n", pClass->sName); + if(pInstr->iP1) { + /* This class inherits from other classes */ + SyString *apExtends; + while(SySetGetNextEntry(&pClass->sExtends, (void **)&apExtends) == SXRET_OK) { + printf("Class '%s' inherits from '%s'\n", pClass->sName.zString, apExtends->zString); + } + } + if(pInstr->iP2) { + /* This class implements some interfaces */ + SyString *apImplements; + while(SySetGetNextEntry(&pClass->sImplements, (void **)&apImplements) == SXRET_OK) { + printf("Class '%s' implements '%s'\n", pClass->sName.zString, apImplements->zString); + } + } + SyStringInitFromBuf(&pClass->sName, "DUPA", 4); + break; + } + /* + * OP_INTERFACE_INIT * * P3 + * Perform additional interface initialization, by adding base interfaces + * to its definition. + */ + case PH7_OP_INTERFACE_INIT: + { + break; + } /* * OP_FOREACH_INIT * P2 P3 * Prepare a foreach step. @@ -6025,6 +6060,12 @@ static const char *VmInstrToString(sxi32 nOp) { case PH7_OP_THROW: zOp = "THROW "; break; + case PH7_OP_CLASS_INIT: + zOp = "CLASS_INIT "; + break; + case PH7_OP_INTERFACE_INIT: + zOp = "INTER_INIT "; + break; case PH7_OP_FOREACH_INIT: zOp = "4EACH_INIT "; break; diff --git a/include/ph7int.h b/include/ph7int.h index 1724a22..cb3e9e2 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1035,6 +1035,8 @@ struct ph7_class { SyHash hMethod; /* Class methods */ sxu32 nLine; /* Line number on which this class was declared */ SySet aInterface; /* Implemented interface container */ + SySet sExtends; /* List of inherited classes / interfaces */ + SySet sImplements; /* List of implemented interfaces */ }; /* Class configuration flags */ #define PH7_CLASS_FINAL 0x001 /* Class is final [cannot be extended] */ @@ -1360,6 +1362,8 @@ enum ph7_vm_op { PH7_OP_CVT_NULL, /* NULL cast */ PH7_OP_CVT_ARRAY, /* Array 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_STEP, /* For each step */ PH7_OP_IS_A, /* Instanceof */