From 323793153ce0f5e1f37e464b7eeba55572b160bb Mon Sep 17 00:00:00 2001 From: Rafal Kupiec Date: Sat, 24 Oct 2026 00:30:45 +0200 Subject: [PATCH] Implement short-circuit evaluation for the null coalescing operator --- engine/compiler.c | 19 +++++++++++++++++++ engine/vm.c | 7 +++++++ 2 files changed, 26 insertions(+) diff --git a/engine/compiler.c b/engine/compiler.c index 575148c..cc77fdb 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -4648,6 +4648,25 @@ static sxi32 PH7_GenStateEmitExprCode( /* All done */ return SXRET_OK; } + if(iVmOp == PH7_OP_NULLC) { + /* The parser stores the source LHS in pRight for this right-associative operator. */ + rc = PH7_GenStateEmitExprCode(&(*pGen), pNode->pRight, iFlags); + if(rc != SXRET_OK) { + return rc; + } + /* Preserve a non-empty LHS without converting it to boolean. */ + PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_JMPNZ, 2, 0, 0, &nJmpIdx); + PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_POP, 1, 0, 0, 0); + rc = PH7_GenStateEmitExprCode(&(*pGen), pNode->pLeft, iFlags); + if(rc != SXRET_OK) { + return rc; + } + pInstr = PH7_VmGetInstr(pGen->pVm, nJmpIdx); + if(pInstr) { + pInstr->iP2 = PH7_VmInstrLength(pGen->pVm); + } + return SXRET_OK; + } /* Generate code for the left tree */ if(pNode->pLeft) { if(iVmOp == PH7_OP_CALL) { diff --git a/engine/vm.c b/engine/vm.c index feca41e..50ccc3b 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2344,11 +2344,18 @@ static sxi32 VmByteCodeExec( * * Take the jump if the top value is not zero (TRUE jump).Pop the top most * entry in the stack if P1 is zero. + * If P1 is 2, test for a non-empty value without converting or popping it. */ case PH7_OP_JMPNZ: if(pTos < pStack) { goto Abort; } + if(pInstr->iP1 == 2) { + if(!PH7_MemObjIsNull(pTos)) { + pc = pInstr->iP2 - 1; + } + break; + } /* Get a boolean value */ if((pTos->nType & MEMOBJ_BOOL) == 0) { PH7_MemObjToBool(pTos);