Implement nominal class and interface types across declarations and calls
Build / AerScript (push) Successful in 37s

This commit is contained in:
2026-10-29 15:48:44 +01:00
parent 5f75319be9
commit 4f6dd45058
6 changed files with 534 additions and 193 deletions
+72 -25
View File
@@ -981,6 +981,36 @@ PH7_PRIVATE sxi32 PH7_CompileArray(ph7_gen_state *pGen, sxi32 iCompileFlag) {
/* Node successfully compiled */
return SXRET_OK;
}
/* Names, not class pointers, survive forward declarations and arena growth. */
static sxu32 GenStateNamedType(ph7_gen_state *pGen, SyString *pName) {
SyString sName;
sxu32 i;
char *zName;
for(i = 0; i < SySetUsed(&pGen->pVm->aTypeNames); i++) {
if(SyStringCmp(pName, (SyString *)SySetAt(&pGen->pVm->aTypeNames, i), SyMemcmp) == 0) {
return ((i + 1) << 12) | MEMOBJ_OBJ;
}
}
zName = SyMemBackendStrDup(&pGen->pVm->sAllocator, pName->zString, pName->nByte);
if(zName == 0 || i >= (MEMOBJ_NAMED >> 12)) {
PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, "PH7 engine is running out-of-memory");
}
SyStringInitFromBuf(&sName, zName, pName->nByte);
if(SySetPut(&pGen->pVm->aTypeNames, &sName) != SXRET_OK) {
PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, "PH7 engine is running out-of-memory");
}
return ((i + 1) << 12) | MEMOBJ_OBJ;
}
static sxi32 GenStateIsNamedDeclaration(SyToken *pIn, SyToken *pEnd) {
if(pIn >= pEnd || (pIn->nType & PH7_TK_ID) == 0 || (pIn->nType & PH7_TK_OP)) {
return FALSE;
}
pIn++;
if(pIn < pEnd && &pIn[1] < pEnd && (pIn->nType & PH7_TK_OSB) && (pIn[1].nType & PH7_TK_CSB)) {
pIn += 2;
}
return pIn < pEnd && (pIn->nType & PH7_TK_DOLLAR);
}
/*
* Compile a closure (anonymous function).
* Closures (also known as anonymous functions), allow the creation of functions
@@ -1010,7 +1040,9 @@ PH7_PRIVATE sxi32 PH7_CompileClosure(ph7_gen_state *pGen, sxi32 iCompileFlag) {
sxu32 nType = 0;
SXUNUSED(iCompileFlag);
sxu32 nKey = (sxu32)(SX_PTR_TO_INT(pGen->pIn->pUserData));
if(nKey & PH7_KEYWORD_BOOL) {
if(pGen->pIn->nType & PH7_TK_ID) {
nType = GenStateNamedType(pGen, &pGen->pIn->sData);
} else if(nKey & PH7_KEYWORD_BOOL) {
nType = MEMOBJ_BOOL;
} else if(nKey & PH7_KEYWORD_CALLBACK) {
nType = MEMOBJ_CALL;
@@ -2057,7 +2089,7 @@ static sxi32 PH7_CompileFor(ph7_gen_state *pGen) {
pTmp = pGen->pEnd;
pGen->pEnd = pEnd;
sxu32 nKey = (sxu32)(SX_PTR_TO_INT(pGen->pIn->pUserData));
if(nKey & (PH7_KEYWORD_AUTO | PH7_KEYWORD_TYPEDEF)) {
if((nKey & (PH7_KEYWORD_AUTO | PH7_KEYWORD_TYPEDEF)) || GenStateIsNamedDeclaration(pGen->pIn, pGen->pEnd)) {
/* Compile variable */
PH7_CompileVar(&(*pGen));
}
@@ -2243,14 +2275,18 @@ static sxi32 PH7_CompileForeach(ph7_gen_state *pGen) {
pTmp = pGen->pEnd;
pGen->pEnd = pCur;
nKey = (sxu32)(SX_PTR_TO_INT(pGen->pIn->pUserData));
if(nKey & (PH7_KEYWORD_AUTO | PH7_KEYWORD_TYPEDEF)) {
if((nKey & (PH7_KEYWORD_AUTO | PH7_KEYWORD_TYPEDEF)) || GenStateIsNamedDeclaration(pGen->pIn, pGen->pEnd)) {
SyToken *pDeclName = &pGen->pIn[2];
if(pGen->pIn[1].nType & PH7_TK_OSB) {
pDeclName += 2;
}
/* Hack to compile variable */
pGen->pEnd->nType = PH7_TK_SEMI;
if(pGen->pIn[3].nType != PH7_TK_SEMI) {
if(pDeclName + 1 != pGen->pEnd) {
PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "foreach: Improper key declaration");
}
/* Extract variable name */
zName = SyMemBackendStrDup(&pGen->pVm->sAllocator, pGen->pIn[2].sData.zString, pGen->pIn[2].sData.nByte);
zName = SyMemBackendStrDup(&pGen->pVm->sAllocator, pDeclName->sData.zString, pDeclName->sData.nByte);
/* Compile variable declaration */
PH7_CompileVar(&(*pGen));
/* Record key name */
@@ -2292,14 +2328,18 @@ static sxi32 PH7_CompileForeach(ph7_gen_state *pGen) {
pTmp = pGen->pEnd;
pGen->pEnd = pCur;
nKey = (sxu32)(SX_PTR_TO_INT(pGen->pIn->pUserData));
if(nKey & (PH7_KEYWORD_AUTO | PH7_KEYWORD_TYPEDEF)) {
if((nKey & (PH7_KEYWORD_AUTO | PH7_KEYWORD_TYPEDEF)) || GenStateIsNamedDeclaration(pGen->pIn, pGen->pEnd)) {
SyToken *pDeclName = &pGen->pIn[2];
if(pGen->pIn[1].nType & PH7_TK_OSB) {
pDeclName += 2;
}
/* Hack to compile variable */
pGen->pEnd->nType = PH7_TK_SEMI;
if(pGen->pIn[3].nType != PH7_TK_SEMI) {
if(pDeclName + 1 != pGen->pEnd) {
PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "foreach: Improper value declaration");
}
/* Extract variable name */
zName = SyMemBackendStrDup(&pGen->pVm->sAllocator, pGen->pIn[2].sData.zString, pGen->pIn[2].sData.nByte);
zName = SyMemBackendStrDup(&pGen->pVm->sAllocator, pDeclName->sData.zString, pDeclName->sData.nByte);
/* Compile variable declaration */
PH7_CompileVar(&(*pGen));
/* Record value name */
@@ -2564,7 +2604,9 @@ static sxi32 PH7_CompileVar(ph7_gen_state *pGen) {
pGen->pIn++;
nKey = (sxu32)(SX_PTR_TO_INT(pGen->pIn->pUserData));
}
if(nKey & PH7_KEYWORD_BOOL) {
if(pGen->pIn->nType & PH7_TK_ID) {
nType = GenStateNamedType(pGen, &pGen->pIn->sData);
} else if(nKey & PH7_KEYWORD_BOOL) {
nType = MEMOBJ_BOOL;
} else if(nKey & PH7_KEYWORD_CALLBACK) {
nType = MEMOBJ_CALL;
@@ -3088,11 +3130,10 @@ static sxi32 PH7_GenStateCollectFuncArgs(ph7_vm_func *pFunc, ph7_gen_state *pGen
/* Argument must be a class instance, record that*/
zDup = SyMemBackendStrDup(&pGen->pVm->sAllocator, pName->zString, pName->nByte);
if(zDup) {
sArg.nType = SXU32_HIGH; /* 0xFFFFFFFF as sentinel */
sArg.nType = GenStateNamedType(pGen, pName);
SyStringInitFromBuf(&sArg.sClass, zDup, pName->nByte);
} else {
/* This should not happen, but fallback to object anyway */
sArg.nType = MEMOBJ_OBJ;
PH7_GenCompileError(pGen, E_ERROR, pIn->nLine, "PH7 engine is running out-of-memory");
}
}
pIn++;
@@ -3855,7 +3896,7 @@ static sxi32 PH7_CompileClassInterface(ph7_gen_state *pGen) {
/* End of interface body */
break;
}
if((pGen->pIn->nType & PH7_TK_KEYWORD) == 0) {
if((pGen->pIn->nType & (PH7_TK_KEYWORD | PH7_TK_ID)) == 0) {
PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine,
"Unexpected token '%z'. Expecting method signature or constant declaration inside interface '%z'",
&pGen->pIn->sData, pName);
@@ -3870,7 +3911,7 @@ static sxi32 PH7_CompileClassInterface(ph7_gen_state *pGen) {
if(nKwrd == PH7_KEYWORD_PUBLIC) {
/* Advance the stream cursor */
pGen->pIn++;
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_KEYWORD) == 0) {
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & (PH7_TK_KEYWORD | PH7_TK_ID)) == 0) {
PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine,
"Expecting method signature inside interface '%z'", pName);
}
@@ -3892,14 +3933,16 @@ static sxi32 PH7_CompileClassInterface(ph7_gen_state *pGen) {
"Cannot declare a static method in an interface '%z'",
pName);
}
if((nKwrd & PH7_KEYWORD_TYPEDEF) == 0) {
if((nKwrd & PH7_KEYWORD_TYPEDEF) == 0 && (pGen->pIn->nType & PH7_TK_ID) == 0) {
PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine,
"Unexpected token '%z', expecting data type for method signature inside interface '%z'",
&pGen->pIn->sData, pName);
}
sxu32 nType = 0;
sxu32 nKey = (sxu32)(SX_PTR_TO_INT(pGen->pIn->pUserData));
if(nKey & PH7_KEYWORD_BOOL) {
if(pGen->pIn->nType & PH7_TK_ID) {
nType = GenStateNamedType(pGen, &pGen->pIn->sData);
} else if(nKey & PH7_KEYWORD_BOOL) {
nType = MEMOBJ_BOOL;
} else if(nKey & PH7_KEYWORD_CALLBACK) {
nType = MEMOBJ_CALL;
@@ -4089,7 +4132,7 @@ static sxi32 PH7_GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) {
/* End of class body */
break;
}
if((pGen->pIn->nType & PH7_TK_KEYWORD) == 0) {
if((pGen->pIn->nType & (PH7_TK_KEYWORD | PH7_TK_ID)) == 0) {
PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine,
"Unexpected token '%z'. Expecting attribute or method declaration inside class '%z'",
&pGen->pIn->sData, pName);
@@ -4102,7 +4145,7 @@ static sxi32 PH7_GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) {
if(nKwrd == PH7_KEYWORD_PUBLIC || nKwrd == PH7_KEYWORD_PRIVATE || nKwrd == PH7_KEYWORD_PROTECTED) {
iProtection = nKwrd;
pGen->pIn++; /* Jump the visibility token */
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_KEYWORD) == 0) {
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & (PH7_TK_KEYWORD | PH7_TK_ID)) == 0) {
PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine,
"Unexpected token '%z'. Expecting attribute or method declaration inside class '%z'",
&pGen->pIn->sData, pName);
@@ -4124,7 +4167,7 @@ static sxi32 PH7_GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) {
/* Static method or attribute,record that */
iAttrflags |= PH7_CLASS_ATTR_STATIC;
pGen->pIn++; /* Jump the static keyword */
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_KEYWORD) == 0) {
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & (PH7_TK_KEYWORD | PH7_TK_ID)) == 0) {
PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine,
"Unexpected token '%z',Expecting attribute or method declaration inside class '%z'",
&pGen->pIn->sData, pName);
@@ -4156,8 +4199,8 @@ static sxi32 PH7_GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) {
pGen->pIn++; /* Jump the static keyword */
}
nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData);
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_KEYWORD) == 0 ||
((nKwrd & PH7_KEYWORD_TYPEDEF) == 0 && pGen->pIn[2].nType != PH7_TK_LPAREN)) {
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & (PH7_TK_KEYWORD | PH7_TK_ID)) == 0 ||
((nKwrd & PH7_KEYWORD_TYPEDEF) == 0 && (pGen->pIn->nType & PH7_TK_ID) == 0 && pGen->pIn[2].nType != PH7_TK_LPAREN)) {
PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine,
"Unexpected token '%z', expecting method declaration after 'virtual' keyword inside class '%z'",
&pGen->pIn->sData, pName);
@@ -4181,21 +4224,23 @@ static sxi32 PH7_GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) {
pGen->pIn++; /* Jump the static keyword */
}
nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData);
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_KEYWORD) == 0 ||
((nKwrd & PH7_KEYWORD_TYPEDEF) == 0 && pGen->pIn[2].nType != PH7_TK_LPAREN)) {
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & (PH7_TK_KEYWORD | PH7_TK_ID)) == 0 ||
((nKwrd & PH7_KEYWORD_TYPEDEF) == 0 && (pGen->pIn->nType & PH7_TK_ID) == 0 && pGen->pIn[2].nType != PH7_TK_LPAREN)) {
PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine,
"Unexpected token '%z', expecting method declaration after 'final' keyword inside class '%z'",
&pGen->pIn->sData, pName);
}
}
if((nKwrd & PH7_KEYWORD_TYPEDEF) == 0) {
if((nKwrd & PH7_KEYWORD_TYPEDEF) == 0 && (pGen->pIn->nType & PH7_TK_ID) == 0) {
PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine,
"Unexpected token '%z', expecting data type for attribute or method declaration inside class '%z'",
&pGen->pIn->sData, pName);
}
sxu32 nType = 0;
sxu32 nKey = (sxu32)(SX_PTR_TO_INT(pGen->pIn->pUserData));
if(nKey & PH7_KEYWORD_BOOL) {
if(pGen->pIn->nType & PH7_TK_ID) {
nType = GenStateNamedType(pGen, &pGen->pIn->sData);
} else if(nKey & PH7_KEYWORD_BOOL) {
nType = MEMOBJ_BOOL;
} else if(nKey & PH7_KEYWORD_CALLBACK) {
nType = MEMOBJ_CALL;
@@ -5384,6 +5429,8 @@ static sxi32 PH7_GenStateCompileChunk(
"Syntax error: Unexpected keyword '%z'",
&pGen->pIn->sData);
}
} else if(GenStateIsNamedDeclaration(pGen->pIn, pGen->pEnd)) {
xCons = PH7_CompileVar;
} else if((pGen->pIn->nType & PH7_TK_ID) && (&pGen->pIn[1] < pGen->pEnd) && (pGen->pIn[1].nType & PH7_TK_COLON /*':'*/)) {
/* Label found [i.e: Out: ],point to the routine responsible of compiling it */
xCons = PH7_CompileLabel;