From dcf37af75e8a97c24c85b5a08d2e2b06b28be4bd Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 21 Jun 2019 00:34:41 +0200 Subject: [PATCH] Implement a NULL-coalescing '??' operator. --- engine/parser.c | 28 +++++++++++++++++++++++++++- engine/vm.c | 13 +++++++++++++ include/ph7int.h | 2 ++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/engine/parser.c b/engine/parser.c index 7f4504c..c73c9bb 100644 --- a/engine/parser.c +++ b/engine/parser.c @@ -86,6 +86,8 @@ static const ph7_expr_op aOpTable[] = { { {"^^", sizeof(char) * 2}, EXPR_OP_LXOR, 16, EXPR_OP_ASSOC_LEFT, PH7_OP_LXOR}, /* Precedence 17,left-associative */ { {"||", sizeof(char) * 2}, EXPR_OP_LOR, 17, EXPR_OP_ASSOC_LEFT, PH7_OP_LOR}, + /* Precedence 18,right-associative */ + { {"??", sizeof(char) * 2}, EXPR_OP_NULLC, 18, EXPR_OP_ASSOC_RIGHT, PH7_OP_NULLC}, /* Ternary operator */ /* Precedence 19,left-associative */ { {"?", sizeof(char)}, EXPR_OP_QUESTY, 19, EXPR_OP_ASSOC_LEFT, 0}, @@ -1074,6 +1076,30 @@ static sxi32 ExprMakeTree(ph7_gen_state *pGen, ph7_expr_node **apNode, sxi32 nTo iLeft = iCur; } } + /* Process right-associative operators with precedence 18 */ + iRight = -1; + for(iCur = nToken - 1 ; iCur >= 0 ; iCur--) { + if(apNode[iCur] == 0) { + continue; + } + pNode = apNode[iCur]; + if(pNode->pOp && pNode->pOp->iPrec == 18 && 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 (Reverse) */ + pNode->pLeft = apNode[iRight]; + pNode->pRight = apNode[iLeft]; + apNode[iLeft] = apNode[iRight] = 0; + } + iRight = iCur; + } /* Handle the ternary operator. (expr1) ? (expr2) : (expr3) * Note that we do not need a precedence loop here since * we are dealing with a single operator. @@ -1139,7 +1165,7 @@ static sxi32 ExprMakeTree(ph7_gen_state *pGen, ph7_expr_node **apNode, sxi32 nTo iLeft = iCur; } /* Process right associative binary operators [i.e: '=','+=','/='] - * Note: All right associative binary operators have precedence 18 + * Note: All right associative binary operators have precedence 20 * so there is no need for a precedence loop here. */ iRight = -1; diff --git a/engine/vm.c b/engine/vm.c index 9eea5cf..0c439b8 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -3879,6 +3879,16 @@ static sxi32 VmByteCodeExec( } break; } + case PH7_OP_NULLC: { + ph7_value *pNos = &pTos[-1]; + int rc; + rc = PH7_MemObjIsNull(pTos); + if(!rc) { + PH7_MemObjStore(pTos, pNos); + } + VmPopOperand(&pTos, 1); + break; + } /* * OP_LOAD_EXCEPTION * P2 P3 * Push an exception in the corresponding container so that @@ -5381,6 +5391,9 @@ static const char *VmInstrToString(sxi32 nOp) { case PH7_OP_NEQ: zOp = "NEQ"; break; + case PH7_OP_NULLC: + zOp = "NULLC"; + break; case PH7_OP_BAND: zOp = "BITAND"; break; diff --git a/include/ph7int.h b/include/ph7int.h index c91e019..1bae627 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1433,6 +1433,7 @@ enum ph7_vm_op { PH7_OP_LAND, /* Logical and '&&' */ PH7_OP_LOR, /* Logical or '||' */ PH7_OP_LXOR, /* Logical xor '^^' */ + PH7_OP_NULLC, /* NULL-coalescing '??' */ PH7_OP_STORE, /* Store Object */ PH7_OP_STORE_IDX, /* Store indexed object */ PH7_OP_STORE_IDX_REF,/* Store indexed object by reference */ @@ -1510,6 +1511,7 @@ enum ph7_expr_id { EXPR_OP_LAND, /* Logical and '&&' */ EXPR_OP_LOR, /* Logical or '||' */ EXPR_OP_LXOR, /* Logical xor '^^' */ + EXPR_OP_NULLC, /* NULL-coalescing '??' */ EXPR_OP_QUESTY, /* Ternary operator '?' */ EXPR_OP_ASSIGN, /* Assignment '=' */ EXPR_OP_ADD_ASSIGN, /* Combined operator: += */