From: Dmitry Volyntsev Date: Fri, 18 Oct 2019 13:34:50 +0000 (+0300) Subject: Querying global object when variable cannot be resolved. X-Git-Tag: 0.3.6~4 X-Git-Url: http://www.kaiwu.me/postgresql/commit/?a=commitdiff_plain;h=c9f37cf3d56cc58199935e065a8c01c2b2069b32;p=njs.git Querying global object when variable cannot be resolved. --- diff --git a/src/njs_disassembler.c b/src/njs_disassembler.c index 184c18c5..7f299146 100644 --- a/src/njs_disassembler.c +++ b/src/njs_disassembler.c @@ -34,6 +34,8 @@ static njs_code_name_t code_names[] = { { NJS_VMCODE_PROPERTY_GET, sizeof(njs_vmcode_prop_get_t), njs_str("PROP GET ") }, + { NJS_VMCODE_GLOBAL_GET, sizeof(njs_vmcode_prop_get_t), + njs_str("GLOBAL GET ") }, { NJS_VMCODE_PROPERTY_INIT, sizeof(njs_vmcode_prop_set_t), njs_str("PROP INIT ") }, { NJS_VMCODE_PROTO_INIT, sizeof(njs_vmcode_prop_set_t), diff --git a/src/njs_generator.c b/src/njs_generator.c index 7d1a3e01..c8690aab 100644 --- a/src/njs_generator.c +++ b/src/njs_generator.c @@ -62,7 +62,7 @@ static njs_int_t njs_generate_name(njs_vm_t *vm, njs_generator_t *generator, static njs_int_t njs_generate_builtin_object(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); static njs_int_t njs_generate_variable(njs_vm_t *vm, njs_generator_t *generator, - njs_parser_node_t *node); + njs_parser_node_t *node, njs_reference_type_t type); static njs_int_t njs_generate_var_statement(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); static njs_int_t njs_generate_if_statement(njs_vm_t *vm, @@ -176,6 +176,8 @@ static njs_int_t njs_generate_node_index_release(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); static njs_int_t njs_generate_index_release(njs_vm_t *vm, njs_generator_t *generator, njs_index_t index); +static njs_int_t njs_generate_global_reference(njs_vm_t *vm, + njs_generator_t *generator, njs_parser_node_t *node, njs_bool_t exception); static njs_int_t njs_generate_reference_error(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node); @@ -577,11 +579,8 @@ njs_generate_name(njs_vm_t *vm, njs_generator_t *generator, njs_vmcode_object_copy_t *copy; var = njs_variable_resolve(vm, node); - if (njs_slow_path(var == NULL)) { - return njs_generate_reference_error(vm, generator, node); - } - if (var->type == NJS_VARIABLE_FUNCTION) { + if (var != NULL && var->type == NJS_VARIABLE_FUNCTION) { node->index = njs_generate_dest_index(vm, generator, node); if (njs_slow_path(node->index == NJS_INDEX_ERROR)) { @@ -596,7 +595,7 @@ njs_generate_name(njs_vm_t *vm, njs_generator_t *generator, return NJS_OK; } - return njs_generate_variable(vm, generator, node); + return njs_generate_variable(vm, generator, node, NJS_REFERENCE); } @@ -628,13 +627,22 @@ njs_generate_builtin_object(njs_vm_t *vm, njs_generator_t *generator, static njs_int_t njs_generate_variable(njs_vm_t *vm, njs_generator_t *generator, - njs_parser_node_t *node) + njs_parser_node_t *node, njs_reference_type_t type) { njs_index_t index; index = njs_variable_index(vm, node); if (njs_slow_path(index == NJS_INDEX_NONE)) { - return njs_generate_reference_error(vm, generator, node); + + switch (type) { + case NJS_DECLARATION: + return njs_generate_reference_error(vm, generator, node); + + case NJS_REFERENCE: + case NJS_TYPEOF: + return njs_generate_global_reference(vm, generator, node, + type == NJS_REFERENCE); + } } node->index = index; @@ -1682,7 +1690,7 @@ njs_generate_assignment(njs_vm_t *vm, njs_generator_t *generator, if (lvalue->token == NJS_TOKEN_NAME) { - ret = njs_generate_variable(vm, generator, lvalue); + ret = njs_generate_variable(vm, generator, lvalue, NJS_DECLARATION); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -1805,7 +1813,7 @@ njs_generate_operation_assignment(njs_vm_t *vm, njs_generator_t *generator, if (lvalue->token == NJS_TOKEN_NAME) { - ret = njs_generate_variable(vm, generator, lvalue); + ret = njs_generate_variable(vm, generator, lvalue, NJS_DECLARATION); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -2239,17 +2247,9 @@ njs_generate_typeof_operation(njs_vm_t *vm, njs_generator_t *generator, expr = node->left; if (expr->token == NJS_TOKEN_NAME) { - expr->index = njs_variable_typeof(vm, expr); - - if (expr->u.reference.variable) { - ret = njs_generate_variable(vm, generator, expr); - if (njs_slow_path(ret != NJS_OK)) { - return NJS_ERROR; - } - - } else { - expr->index = njs_value_index(vm, &njs_value_undefined, - generator->runtime); + ret = njs_generate_variable(vm, generator, expr, NJS_TYPEOF); + if (njs_slow_path(ret != NJS_OK)) { + return NJS_ERROR; } } else { @@ -2291,7 +2291,7 @@ njs_generate_inc_dec_operation(njs_vm_t *vm, njs_generator_t *generator, if (lvalue->token == NJS_TOKEN_NAME) { - ret = njs_generate_variable(vm, generator, lvalue); + ret = njs_generate_variable(vm, generator, lvalue, NJS_DECLARATION); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -2668,7 +2668,7 @@ njs_generate_function_call(njs_vm_t *vm, njs_generator_t *generator, name = node->left; } else { - ret = njs_generate_variable(vm, generator, node); + ret = njs_generate_variable(vm, generator, node, NJS_REFERENCE); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -2676,10 +2676,6 @@ njs_generate_function_call(njs_vm_t *vm, njs_generator_t *generator, name = node; } - if (node->u.reference.not_defined) { - return NJS_OK; - } - njs_generate_code(generator, njs_vmcode_function_frame_t, func, NJS_VMCODE_FUNCTION_FRAME, 2); func_offset = njs_code_offset(generator, func); @@ -3360,6 +3356,51 @@ njs_generate_index_release(njs_vm_t *vm, njs_generator_t *generator, } +static njs_int_t +njs_generate_global_reference(njs_vm_t *vm, njs_generator_t *generator, + njs_parser_node_t *node, njs_bool_t exception) +{ + njs_str_t *name; + njs_int_t ret; + njs_index_t index; + njs_value_t property; + njs_vmcode_prop_get_t *prop_get; + + index = njs_generate_dest_index(vm, generator, node); + if (njs_slow_path(index == NJS_INDEX_ERROR)) { + return NJS_ERROR; + } + + njs_generate_code(generator, njs_vmcode_prop_get_t, prop_get, + exception ? NJS_VMCODE_GLOBAL_GET: NJS_VMCODE_PROPERTY_GET, 3); + + prop_get->value = index; + prop_get->object = NJS_INDEX_GLOBAL_OBJECT; + + /* FIXME: cache keys in a hash. */ + + name = &node->u.reference.name; + + ret = njs_string_set(vm, &property, name->start, name->length); + if (njs_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } + + prop_get->property = njs_value_index(vm, &property, generator->runtime); + if (njs_slow_path(prop_get->property == NJS_INDEX_NONE)) { + return NJS_ERROR; + } + + node->index = index; + + if (!exception) { + return NJS_OK; + } + + return njs_generate_reference_error(vm, generator, node); +} + + static njs_int_t njs_generate_reference_error(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node) diff --git a/src/njs_vmcode.c b/src/njs_vmcode.c index bb90be00..382a4477 100644 --- a/src/njs_vmcode.c +++ b/src/njs_vmcode.c @@ -209,6 +209,23 @@ next: pc += sizeof(njs_vmcode_3addr_t); goto next; + case NJS_VMCODE_GLOBAL_GET: + get = (njs_vmcode_prop_get_t *) pc; + retval = njs_vmcode_operand(vm, get->value); + + ret = njs_value_property(vm, value1, value2, retval); + if (njs_slow_path(ret == NJS_ERROR)) { + goto error; + } + + pc += sizeof(njs_vmcode_prop_get_t); + + if (ret == NJS_OK) { + pc += sizeof(njs_vmcode_reference_error_t); + } + + goto next; + /* * njs_vmcode_try_return() saves a return value to use it later by * njs_vmcode_finally(), and jumps to the nearest try_break block. diff --git a/src/njs_vmcode.h b/src/njs_vmcode.h index a2ba25da..334f30f4 100644 --- a/src/njs_vmcode.h +++ b/src/njs_vmcode.h @@ -72,6 +72,7 @@ typedef uint8_t njs_vmcode_operation_t; #define NJS_VMCODE_DECREMENT VMCODE1(4) #define NJS_VMCODE_POST_DECREMENT VMCODE1(5) #define NJS_VMCODE_TRY_RETURN VMCODE1(6) +#define NJS_VMCODE_GLOBAL_GET VMCODE1(7) #define NJS_VMCODE_LESS VMCODE1(8) #define NJS_VMCODE_GREATER VMCODE1(9) diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index 032b6c41..65051bf4 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -2694,6 +2694,10 @@ static njs_unit_test_t njs_test[] = "}; t"), njs_str("A") }, + { njs_str("[isNaN, undefined, isFinite]." + "map((v)=>{switch(v) { case isNaN: return 1; default: return 0;}})"), + njs_str("1,0,0") }, + /* continue. */ { njs_str("continue"), @@ -9319,6 +9323,18 @@ static njs_unit_test_t njs_test[] = { njs_str("this.a = 1; this.a"), njs_str("1") }, + { njs_str("this.a = 1; a"), + njs_str("1") }, + + { njs_str("this.a = 2; this.b = 3; a * b - a"), + njs_str("4") }, + + { njs_str("this.a = 1; a()"), + njs_str("TypeError: number is not a function") }, + + { njs_str("this.a = ()=>1; a()"), + njs_str("1") }, + { njs_str("this.undefined = 42"), njs_str("TypeError: Cannot assign to read-only property \"undefined\" of object") }, @@ -13084,6 +13100,12 @@ static njs_unit_test_t njs_test[] = { njs_str("isNaN.length"), njs_str("1") }, + { njs_str("typeof isNaN"), + njs_str("function") }, + + { njs_str("typeof isNaN.length"), + njs_str("number") }, + { njs_str("isNaN()"), njs_str("true") },