Implement exponentiation (**) operator
All checks were successful
Build / AerScript (push) Successful in 40s

This commit is contained in:
Rafal Kupiec 2025-08-29 22:04:55 +02:00
parent 8ac9b148d1
commit d73eb9b5b2
Signed by: belliash
GPG Key ID: 4E829243E0CFE6B4
4 changed files with 99 additions and 3 deletions

View File

@ -4742,6 +4742,13 @@ static sxi32 PH7_GenStateEmitExprCode(
(void)PH7_VmPopInstr(pGen->pVm);
}
}
} else if(pNode->pOp->iPrec == 20 && pNode->pOp->iOp != EXPR_OP_ASSIGN) {
pInstr = PH7_VmPeekInstr(pGen->pVm);
if(pInstr) {
if(pInstr->iOp != PH7_OP_LOAD_IDX) {
p3 = pInstr->p3;
}
}
}
}
if(iVmOp > 0) {

View File

@ -52,8 +52,10 @@ static const ph7_expr_op aOpTable[] = {
{ {"(resource)", sizeof("(resource)") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_RES},
{ {"(void)", sizeof("(void)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_VOID },
/* Binary operators */
/* Precedence 6,non-associative */
{ {"is", sizeof("is") - 1}, EXPR_OP_IS, 6, EXPR_OP_NON_ASSOC, PH7_OP_IS},
/* Precedence 5,non-associative */
{ {"is", sizeof("is") - 1}, EXPR_OP_IS, 5, EXPR_OP_NON_ASSOC, PH7_OP_IS},
/* Precedence 6, right-associative */
{ {"**", sizeof(char) * 2}, EXPR_OP_POW, 6, EXPR_OP_ASSOC_RIGHT, PH7_OP_POW},
/* Precedence 7,left-associative */
{ {"*", sizeof(char)}, EXPR_OP_MUL, 7, EXPR_OP_ASSOC_LEFT, PH7_OP_MUL},
{ {"/", sizeof(char)}, EXPR_OP_DIV, 7, EXPR_OP_ASSOC_LEFT, PH7_OP_DIV},
@ -97,6 +99,7 @@ static const ph7_expr_op aOpTable[] = {
{ {"+=", sizeof(char) * 2}, EXPR_OP_ADD_ASSIGN, 20, EXPR_OP_ASSOC_RIGHT, PH7_OP_ADD_STORE },
{ {"-=", sizeof(char) * 2}, EXPR_OP_SUB_ASSIGN, 20, EXPR_OP_ASSOC_RIGHT, PH7_OP_SUB_STORE },
{ {"*=", sizeof(char) * 2}, EXPR_OP_MUL_ASSIGN, 20, EXPR_OP_ASSOC_RIGHT, PH7_OP_MUL_STORE },
{ {"**=", sizeof(char) * 3}, EXPR_OP_POW_ASSIGN, 20, EXPR_OP_ASSOC_RIGHT, PH7_OP_POW_STORE },
{ {"/=", sizeof(char) * 2}, EXPR_OP_DIV_ASSIGN, 20, EXPR_OP_ASSOC_RIGHT, PH7_OP_DIV_STORE },
{ {"%=", sizeof(char) * 2}, EXPR_OP_MOD_ASSIGN, 20, EXPR_OP_ASSOC_RIGHT, PH7_OP_MOD_STORE },
{ {"&=", sizeof(char) * 2}, EXPR_OP_AND_ASSIGN, 20, EXPR_OP_ASSOC_RIGHT, PH7_OP_BAND_STORE },
@ -1020,8 +1023,32 @@ static sxi32 ExprMakeTree(ph7_gen_state *pGen, ph7_expr_node **apNode, sxi32 nTo
iLeft = iCur;
}
}
/* Handle right associative binary operators with precedence 6 */
iRight = -1;
for(iCur = nToken - 1; iCur >= 0; iCur--) {
if(apNode[iCur] == 0) {
continue;
}
pNode = apNode[iCur];
if(pNode->pOp && pNode->pOp->iPrec == 6 && pNode->pLeft == 0) {
/* Get the left node */
iLeft = iCur - 1;
while(iLeft >= 0 && apNode[iLeft] == 0) {
iLeft--;
}
if(iLeft < 0 || iRight < 0 || !NODE_ISTERM(iRight) || !NODE_ISTERM(iLeft)) {
/* Syntax error */
PH7_GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "'%z': Missing/Invalid operand", &pNode->pOp->sOp);
}
/* Link the node to the tree */
pNode->pLeft = apNode[iRight];
pNode->pRight = apNode[iLeft];
apNode[iLeft] = apNode[iRight] = 0;
}
iRight = iCur;
}
/* Process left and non-associative binary operators [i.e: *,/,&&,||...]*/
for(i = 6 ; i < 18 ; i++) {
for(i = 5 ; i < 18 ; i++) {
iLeft = -1;
for(iCur = 0 ; iCur < nToken ; ++iCur) {
if(apNode[iCur] == 0) {

View File

@ -7,6 +7,7 @@
* Rafal Kupiec <belliash@codingworkshop.eu.org>
* David Carlier <devnexen@gmail.com>
*/
#include <math.h>
#include "ph7int.h"
/*
@ -2979,6 +2980,63 @@ static sxi32 VmByteCodeExec(
VmPopOperand(&pTos, 1);
break;
}
/* OP_POW * * *
* OP_POW_STORE * * *
*
* Pop the top two elements from the stack, perform an exponentiation,
* and push the result back onto the stack.
*/
case PH7_OP_POW:
case PH7_OP_POW_STORE: {
SyString sName;
ph7_value *pNos = &pTos[-1];
/* Force the operand to be numeric */
if(pNos < pStack) {
goto Abort;
}
PH7_MemObjToNumeric(pTos);
PH7_MemObjToNumeric(pNos);
/* Perform the requested operation */
if(MEMOBJ_REAL & (pTos->nType | pNos->nType)) {
/* Floating point arithmetic */
ph7_real a, b, r;
if((pTos->nType & MEMOBJ_REAL) == 0) {
PH7_MemObjToReal(pTos);
}
if((pNos->nType & MEMOBJ_REAL) == 0) {
PH7_MemObjToReal(pNos);
}
a = pNos->x.rVal;
b = pTos->x.rVal;
r = pow(b, a);
/* Push the result */
pNos->x.rVal = r;
MemObjSetType(pNos, MEMOBJ_REAL);
} else {
/* Integer arithmetic */
sxi64 a, b, r;
a = pNos->x.iVal;
b = pTos->x.iVal;
r = (sxi64)pow((double)b, (double)a);
/* Push the result */
pNos->x.iVal = r;
MemObjSetType(pNos, MEMOBJ_INT);
}
if(pInstr->iOp == PH7_OP_POW_STORE) {
ph7_value *pObj;
if(pTos->nIdx == SXU32_HIGH) {
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot perform assignment on a constant class attribute");
} else if((pObj = (ph7_value *)SySetAt(&pVm->aMemObj, pTos->nIdx)) != 0) {
if(pNos->nType != pObj->nType && PH7_CheckVarCompat(pNos, pObj->nType) != SXRET_OK) {
SyStringInitFromBuf(&sName, pInstr->p3, SyStrlen((const char *)pInstr->p3));
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '$%z'", &sName);
};
PH7_MemObjStore(pNos, pObj);
}
}
VmPopOperand(&pTos, 1);
break;
}
/* OP_ADD P1 P2 *
*
* Pop the top two elements from the stack, add them together,

View File

@ -1403,6 +1403,7 @@ enum ph7_vm_op {
PH7_OP_BITNOT, /* Bitwise not '~' */
PH7_OP_LNOT, /* Logical not '!' */
PH7_OP_MUL, /* Multiplication '*' */
PH7_OP_POW, /* POW '**' */
PH7_OP_DIV, /* Division '/' */
PH7_OP_MOD, /* Modulus '%' */
PH7_OP_ADD, /* Add '+' */
@ -1437,6 +1438,7 @@ enum ph7_vm_op {
PH7_OP_ADD_STORE, /* Add and store '+=' */
PH7_OP_SUB_STORE, /* Sub and store '-=' */
PH7_OP_MUL_STORE, /* Mul and store '*=' */
PH7_OP_POW_STORE, /* Pow and store '**=' */
PH7_OP_DIV_STORE, /* Div and store '/=' */
PH7_OP_MOD_STORE, /* Mod and store '%=' */
PH7_OP_SHL_STORE, /* Shift left and store '>>=' */
@ -1479,6 +1481,7 @@ enum ph7_expr_id {
EXPR_OP_TYPECAST, /* Type cast [i.e: (int),(float),(string)...] */
EXPR_OP_IS, /* is */
EXPR_OP_LOGNOT, /* logical not ! */
EXPR_OP_POW, /* Exponentiation '**' */
EXPR_OP_MUL, /* Multiplication */
EXPR_OP_DIV, /* division */
EXPR_OP_MOD, /* Modulus */
@ -1505,6 +1508,7 @@ enum ph7_expr_id {
EXPR_OP_ADD_ASSIGN, /* Combined operator: += */
EXPR_OP_SUB_ASSIGN, /* Combined operator: -= */
EXPR_OP_MUL_ASSIGN, /* Combined operator: *= */
EXPR_OP_POW_ASSIGN, /* Combined operator: **= */
EXPR_OP_DIV_ASSIGN, /* Combined operator: /= */
EXPR_OP_MOD_ASSIGN, /* Combined operator: %= */
EXPR_OP_AND_ASSIGN, /* Combined operator: &= */