From: Dmitry Volyntsev Date: Wed, 11 Feb 2026 16:16:00 +0000 (-0800) Subject: Added support for ??= operator. X-Git-Tag: 0.9.6~4 X-Git-Url: http://www.kaiwu.me/postgresql/commit/?a=commitdiff_plain;h=aa8ff7d04634080d3a28a207d688cd21b9b5392b;p=njs.git Added support for ??= operator. --- diff --git a/src/njs_generator.c b/src/njs_generator.c index a3a0adaf..9de1a145 100644 --- a/src/njs_generator.c +++ b/src/njs_generator.c @@ -665,6 +665,7 @@ njs_generate(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node) case NJS_TOKEN_LOGICAL_OR_ASSIGNMENT: case NJS_TOKEN_LOGICAL_AND_ASSIGNMENT: + case NJS_TOKEN_COALESCE_ASSIGNMENT: return njs_generate_logical_assignment(vm, generator, node); case NJS_TOKEN_BITWISE_OR: diff --git a/src/njs_lexer.c b/src/njs_lexer.c index 30febb14..b5c2ce12 100644 --- a/src/njs_lexer.c +++ b/src/njs_lexer.c @@ -276,8 +276,13 @@ static const njs_lexer_multi_t njs_greater_token[] = { }; +static const njs_lexer_multi_t njs_coalesce_assignment_token[] = { + { '=', NJS_TOKEN_COALESCE_ASSIGNMENT, 0, NULL }, +}; + + static const njs_lexer_multi_t njs_conditional_token[] = { - { '?', NJS_TOKEN_COALESCE, 0, NULL }, + { '?', NJS_TOKEN_COALESCE, 1, njs_coalesce_assignment_token }, }; diff --git a/src/njs_lexer.h b/src/njs_lexer.h index 331eb52e..9dd21063 100644 --- a/src/njs_lexer.h +++ b/src/njs_lexer.h @@ -52,6 +52,7 @@ typedef enum { NJS_TOKEN_BITWISE_AND_ASSIGNMENT, NJS_TOKEN_LOGICAL_OR_ASSIGNMENT, NJS_TOKEN_LOGICAL_AND_ASSIGNMENT, + NJS_TOKEN_COALESCE_ASSIGNMENT, NJS_TOKEN_INCREMENT, NJS_TOKEN_DECREMENT, diff --git a/src/njs_parser.c b/src/njs_parser.c index 8d2a778e..669f619b 100644 --- a/src/njs_parser.c +++ b/src/njs_parser.c @@ -4618,6 +4618,11 @@ njs_parser_assignment_operator(njs_parser_t *parser, njs_lexer_token_t *token, operation = NJS_VMCODE_TEST_IF_FALSE; break; + case NJS_TOKEN_COALESCE_ASSIGNMENT: + njs_thread_log_debug("JS: ?\?="); + operation = NJS_VMCODE_COALESCE; + break; + default: return njs_parser_stack_pop(parser); } @@ -9568,6 +9573,7 @@ njs_parser_serialize_node(njs_chb_t *chain, njs_parser_node_t *node) njs_token_serialize(NJS_TOKEN_BITWISE_AND_ASSIGNMENT); njs_token_serialize(NJS_TOKEN_LOGICAL_OR_ASSIGNMENT); njs_token_serialize(NJS_TOKEN_LOGICAL_AND_ASSIGNMENT); + njs_token_serialize(NJS_TOKEN_COALESCE_ASSIGNMENT); njs_token_serialize(NJS_TOKEN_EQUAL); njs_token_serialize(NJS_TOKEN_NOT_EQUAL); njs_token_serialize(NJS_TOKEN_STRICT_EQUAL); diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index bff84868..bbe70ebb 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -1625,6 +1625,75 @@ static njs_unit_test_t njs_test[] = { njs_str("1 &&= 2"), njs_str("ReferenceError: Invalid left-hand side in assignment") }, + /* Logical assignment: ??= */ + + { njs_str("var a = null; a ?\?= 5; a"), + njs_str("5") }, + { njs_str("var a = undefined; a ?\?= 5; a"), + njs_str("5") }, + { njs_str("var a = 0; a ?\?= 5; a"), + njs_str("0") }, + { njs_str("var a = ''; a ?\?= 'x'; a"), + njs_str("") }, + { njs_str("var a = false; a ?\?= true; a"), + njs_str("false") }, + { njs_str("var a = 1; a ?\?= 5; a"), + njs_str("1") }, + + /* ??= short-circuit: RHS not evaluated */ + + { njs_str("var a = 1; var b = 0; a ?\?= (b = 2); b"), + njs_str("0") }, + { njs_str("var a = null; var b = 0; a ?\?= (b = 2); b"), + njs_str("2") }, + + /* ??= property targets */ + + { njs_str("var o = {a: null}; o.a ?\?= 5; o.a"), + njs_str("5") }, + { njs_str("var o = {a: 0}; o.a ?\?= 5; o.a"), + njs_str("0") }, + { njs_str("var o = {a: null}; o['a'] ?\?= 5; o.a"), + njs_str("5") }, + + /* ??= expression result value */ + + { njs_str("var a = 1; (a ?\?= 5)"), + njs_str("1") }, + { njs_str("var a = null; (a ?\?= 5)"), + njs_str("5") }, + + /* ??= const error */ + + { njs_str("const a = 1; a ?\?= 2"), + njs_str("1") }, + { njs_str("const a = null; a ?\?= 2"), + njs_str("TypeError: assignment to constant variable") }, + + /* ??= getter/setter short-circuit */ + + { njs_str("var log = '';" + "var o = {" + " get x() {log += 'g'; return 1}," + " set x(v) {log += 's'}" + "};" + "o.x ?\?= 2;" + "log"), + njs_str("g") }, + { njs_str("var log = '';" + "var o = {" + " get x() {log += 'g'; return null}," + " set x(v) {log += 's'}" + "};" + "o.x ?\?= 2;" + "log"), + njs_str("gs") }, + + /* ??= non-lvalue error */ + + { njs_str("1 ?\?= 2"), + njs_str("ReferenceError: Invalid left-hand side in assignment") }, + /* Optional chaining: property access. */ { njs_str("var o = {a: 1}; o?.a"),