Fix value comparison and sorting semantics
Build / AerScript (push) Successful in 31s

This commit is contained in:
2026-11-05 22:26:00 +01:00
parent 3c3c15281a
commit d98f6a8e91
10 changed files with 1956 additions and 681 deletions
+55 -10
View File
@@ -3283,8 +3283,16 @@ Resume:
iRes = VmInstanceOf(pVm, pThis->pClass, pClass);
}
} else {
rc = PH7_MemObjCmp(pNos, pTos, FALSE, 0);
iRes = rc == 0;
/* Value comparison fallback: follows the typed comparison
* contract. Incomparable categories yield FALSE [no match]
* rather than a fatal error, since is is a type test with
* a value-comparison fallback. */
if(PH7_MemObjComparable(pNos, pTos)) {
rc = PH7_MemObjCmp(pNos, pTos, FALSE, 0, 0);
iRes = rc == 0;
} else {
iRes = 0;
}
}
}
/* Push result */
@@ -4823,8 +4831,11 @@ Resume:
if(pNos < pStack) {
goto Abort;
}
rc = PH7_MemObjCmp(pNos, pTos, FALSE, 0);
if(pInstr->iOp == PH7_OP_EQ) {
rc = PH7_MemObjCmp(pNos, pTos, FALSE, 0, pInstr->iOp == PH7_OP_EQ ? "==" : "!=");
if(rc == SXERR_NOMATCH) {
/* NaN operand: == is FALSE, != is TRUE */
rc = pInstr->iOp != PH7_OP_EQ;
} else if(pInstr->iOp == PH7_OP_EQ) {
rc = rc == 0;
} else {
rc = rc != 0;
@@ -4870,8 +4881,19 @@ Resume:
if(pNos < pStack) {
goto Abort;
}
rc = PH7_MemObjCmp(pNos, pTos, FALSE, 0);
if(pInstr->iOp == PH7_OP_LE) {
if(!PH7_MemObjOrderable(pNos, pTos)) {
/* Only two numbers or two strings define an order.
* The diagnostic is terminal: abort the execution
* instead of falling through into a second,
* contradictory comparison. */
PH7_VmThrowNoOrder(pNos, pTos, pInstr->iOp == PH7_OP_LE ? "<=" : "<");
goto Abort;
}
rc = PH7_MemObjCmp(pNos, pTos, FALSE, 0, pInstr->iOp == PH7_OP_LE ? "<=" : "<");
if(rc == SXERR_NOMATCH) {
/* NaN operand: ordering is always FALSE */
rc = 0;
} else if(pInstr->iOp == PH7_OP_LE) {
rc = rc < 1;
} else {
rc = rc < 0;
@@ -4917,8 +4939,19 @@ Resume:
if(pNos < pStack) {
goto Abort;
}
rc = PH7_MemObjCmp(pNos, pTos, FALSE, 0);
if(pInstr->iOp == PH7_OP_GE) {
if(!PH7_MemObjOrderable(pNos, pTos)) {
/* Only two numbers or two strings define an order.
* The diagnostic is terminal: abort the execution
* instead of falling through into a second,
* contradictory comparison. */
PH7_VmThrowNoOrder(pNos, pTos, pInstr->iOp == PH7_OP_GE ? ">=" : ">");
goto Abort;
}
rc = PH7_MemObjCmp(pNos, pTos, FALSE, 0, pInstr->iOp == PH7_OP_GE ? ">=" : ">");
if(rc == SXERR_NOMATCH) {
/* NaN operand: ordering is always FALSE */
rc = 0;
} else if(pInstr->iOp == PH7_OP_GE) {
rc = rc >= 0;
} else {
rc = rc > 0;
@@ -5750,8 +5783,20 @@ Resume:
nTarget = pc + 1;
goto Unwind;
}
/* Compare the two expression */
rc = PH7_MemObjCmp(&sValue, &sCaseValue, FALSE, 0);
/* Compare the two expressions.
* Matching follows the typed comparison contract: only
* values of the same comparison category can match;
* incomparable case labels are skipped [no match]. */
if(PH7_MemObjComparable(&sValue, &sCaseValue)) {
rc = PH7_MemObjCmp(&sValue, &sCaseValue, FALSE, 0, 0);
if(rc == SXERR_NOMATCH) {
/* NaN operand never matches a case label */
rc = 1;
}
} else {
/* Different categories: fall through to the next case */
rc = 1;
}
PH7_MemObjRelease(&sValue);
PH7_MemObjRelease(&sCaseValue);
if(rc == 0) {