Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # HG changeset patch
- # User Dmitry Volyntsev <xeioex@nginx.com>
- # Date 1565288475 -10800
- # Thu Aug 08 21:21:15 2019 +0300
- # Node ID 2ba2acdef6527f3b07e0987265841c7752d3286c
- # Parent 239f3511397bfbcd89de5b7433daaeaa732b1adc
- Fixed njs_vmcode_property_init().
- Function assumed obj->__proto__ is never NULL, whereas it can became
- NULL after __proto__: null assignment.
- diff --git a/src/njs_vmcode.c b/src/njs_vmcode.c
- --- a/src/njs_vmcode.c
- +++ b/src/njs_vmcode.c
- @@ -1136,18 +1136,21 @@ njs_vmcode_property_init(njs_vm_t *vm, n
- obj = njs_object(value);
- - ret = njs_lvlhsh_find(&obj->__proto__->shared_hash, &lhq);
- - if (ret == NJS_OK) {
- - prop = lhq.value;
- + if (obj->__proto__ != NULL) {
- + /* obj->__proto__ can be NULL after __proto__: null */
- + ret = njs_lvlhsh_find(&obj->__proto__->shared_hash, &lhq);
- + if (ret == NJS_OK) {
- + prop = lhq.value;
- - if (prop->type == NJS_PROPERTY_HANDLER) {
- - ret = prop->value.data.u.prop_handler(vm, value, init,
- - &vm->retval);
- - if (njs_slow_path(ret != NJS_OK)) {
- - return ret;
- + if (prop->type == NJS_PROPERTY_HANDLER) {
- + ret = prop->value.data.u.prop_handler(vm, value, init,
- + &vm->retval);
- + if (njs_slow_path(ret != NJS_OK)) {
- + return ret;
- + }
- +
- + break;
- }
- -
- - break;
- }
- }
- diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c
- --- a/src/test/njs_unit_test.c
- +++ b/src/test/njs_unit_test.c
- @@ -8776,6 +8776,12 @@ static njs_unit_test_t njs_test[] =
- { njs_str("({}).__proto__ = null"),
- njs_str("null") },
- + { njs_str("({__proto__:null}).__proto__"),
- + njs_str("undefined") },
- +
- + { njs_str("({__proto__:null, a:1}).a"),
- + njs_str("1") },
- +
- { njs_str("({__proto__: []}) instanceof Array"),
- njs_str("true") },
- # HG changeset patch
- # User hongzhidao <hongzhidao@gmail.com>
- # Date 1565250738 14400
- # Thu Aug 08 03:52:18 2019 -0400
- # Node ID 97e6b099ec1aa3a400afd023b4791c2d788583ea
- # Parent 2ba2acdef6527f3b07e0987265841c7752d3286c
- Added getter/setter literal support.
- diff --git a/src/njs_disassembler.c b/src/njs_disassembler.c
- --- a/src/njs_disassembler.c
- +++ b/src/njs_disassembler.c
- @@ -36,15 +36,15 @@ static njs_code_name_t code_names[] = {
- njs_str("OBJECT COPY ") },
- { NJS_VMCODE_PROPERTY_GET, sizeof(njs_vmcode_prop_get_t),
- - njs_str("PROPERTY GET ") },
- + njs_str("PROP GET ") },
- { NJS_VMCODE_PROPERTY_INIT, sizeof(njs_vmcode_prop_set_t),
- - njs_str("PROPERTY INIT ") },
- + njs_str("PROP INIT ") },
- { NJS_VMCODE_PROPERTY_SET, sizeof(njs_vmcode_prop_set_t),
- - njs_str("PROPERTY SET ") },
- + njs_str("PROP SET ") },
- { NJS_VMCODE_PROPERTY_IN, sizeof(njs_vmcode_3addr_t),
- - njs_str("PROPERTY IN ") },
- + njs_str("PROP IN ") },
- { NJS_VMCODE_PROPERTY_DELETE, sizeof(njs_vmcode_3addr_t),
- - njs_str("PROPERTY DELETE ") },
- + njs_str("PROP DELETE ") },
- { NJS_VMCODE_INSTANCE_OF, sizeof(njs_vmcode_instance_of_t),
- njs_str("INSTANCE OF ") },
- @@ -178,6 +178,7 @@ njs_disassemble(u_char *start, u_char *e
- njs_vmcode_equal_jump_t *equal;
- njs_vmcode_prop_foreach_t *prop_foreach;
- njs_vmcode_method_frame_t *method;
- + njs_vmcode_prop_accessor_t *prop_accessor;
- njs_vmcode_try_trampoline_t *try_tramp;
- njs_vmcode_function_frame_t *function;
- @@ -305,7 +306,7 @@ njs_disassemble(u_char *start, u_char *e
- if (operation == NJS_VMCODE_PROPERTY_FOREACH) {
- prop_foreach = (njs_vmcode_prop_foreach_t *) p;
- - njs_printf("%05uz PROPERTY FOREACH %04Xz %04Xz +%uz\n",
- + njs_printf("%05uz PROP FOREACH %04Xz %04Xz +%uz\n",
- p - start, (size_t) prop_foreach->next,
- (size_t) prop_foreach->object,
- (size_t) prop_foreach->offset);
- @@ -317,7 +318,7 @@ njs_disassemble(u_char *start, u_char *e
- if (operation == NJS_VMCODE_PROPERTY_NEXT) {
- prop_next = (njs_vmcode_prop_next_t *) p;
- - njs_printf("%05uz PROPERTY NEXT %04Xz %04Xz %04Xz %uz\n",
- + njs_printf("%05uz PROP NEXT %04Xz %04Xz %04Xz %uz\n",
- p - start, (size_t) prop_next->retval,
- (size_t) prop_next->object, (size_t) prop_next->next,
- (size_t) prop_next->offset);
- @@ -327,6 +328,22 @@ njs_disassemble(u_char *start, u_char *e
- continue;
- }
- + if (operation == NJS_VMCODE_PROPERTY_ACCESSOR) {
- + prop_accessor = (njs_vmcode_prop_accessor_t *) p;
- +
- + njs_printf("%05uz PROP %s ACCESSOR %04Xz %04Xz %04Xz\n",
- + p - start,
- + (prop_accessor->type == NJS_OBJECT_PROP_GETTER)
- + ? "GET" : "SET",
- + (size_t) prop_accessor->value,
- + (size_t) prop_accessor->object,
- + (size_t) prop_accessor->property);
- +
- + p += sizeof(njs_vmcode_prop_accessor_t);
- +
- + continue;
- + }
- +
- if (operation == NJS_VMCODE_TRY_START) {
- try_start = (njs_vmcode_try_start_t *) p;
- diff --git a/src/njs_generator.c b/src/njs_generator.c
- --- a/src/njs_generator.c
- +++ b/src/njs_generator.c
- @@ -119,6 +119,8 @@ static njs_int_t njs_generate_operation_
- njs_generator_t *generator, njs_parser_node_t *node);
- static njs_int_t njs_generate_object(njs_vm_t *vm, njs_generator_t *generator,
- njs_parser_node_t *node);
- +static njs_int_t njs_generate_property_accessor(njs_vm_t *vm,
- + njs_generator_t *generator, njs_parser_node_t *node);
- static njs_int_t njs_generate_array(njs_vm_t *vm, njs_generator_t *generator,
- njs_parser_node_t *node);
- static njs_int_t njs_generate_function(njs_vm_t *vm, njs_generator_t *generator,
- @@ -398,6 +400,10 @@ njs_generator(njs_vm_t *vm, njs_generato
- case NJS_TOKEN_OBJECT:
- return njs_generate_object(vm, generator, node);
- + case NJS_TOKEN_PROPERTY_GETTER:
- + case NJS_TOKEN_PROPERTY_SETTER:
- + return njs_generate_property_accessor(vm, generator, node);
- +
- case NJS_TOKEN_ARRAY:
- return njs_generate_array(vm, generator, node);
- @@ -1896,6 +1902,49 @@ njs_generate_object(njs_vm_t *vm, njs_ge
- static njs_int_t
- +njs_generate_property_accessor(njs_vm_t *vm, njs_generator_t *generator,
- + njs_parser_node_t *node)
- +{
- + njs_int_t ret;
- + njs_parser_node_t *lvalue, *function, *object, *property;
- + njs_vmcode_prop_accessor_t *accessor;
- +
- + lvalue = node->left;
- + function = node->right;
- +
- + object = lvalue->left;
- +
- + ret = njs_generator(vm, generator, object);
- + if (njs_slow_path(ret != NJS_OK)) {
- + return ret;
- + }
- +
- + property = lvalue->right;
- +
- + ret = njs_generator(vm, generator, property);
- + if (njs_slow_path(ret != NJS_OK)) {
- + return ret;
- + }
- +
- + ret = njs_generator(vm, generator, function);
- + if (njs_slow_path(ret != NJS_OK)) {
- + return ret;
- + }
- +
- + njs_generate_code(generator, njs_vmcode_prop_accessor_t, accessor,
- + NJS_VMCODE_PROPERTY_ACCESSOR, 3);
- +
- + accessor->value = function->index;
- + accessor->object = object->index;
- + accessor->property = property->index;
- + accessor->type = (node->token == NJS_TOKEN_PROPERTY_GETTER)
- + ? NJS_OBJECT_PROP_GETTER : NJS_OBJECT_PROP_SETTER;
- +
- + return NJS_OK;
- +}
- +
- +
- +static njs_int_t
- njs_generate_array(njs_vm_t *vm, njs_generator_t *generator,
- njs_parser_node_t *node)
- {
- diff --git a/src/njs_lexer.h b/src/njs_lexer.h
- --- a/src/njs_lexer.h
- +++ b/src/njs_lexer.h
- @@ -125,6 +125,8 @@ typedef enum {
- NJS_TOKEN_PROPERTY,
- NJS_TOKEN_PROPERTY_INIT,
- NJS_TOKEN_PROPERTY_DELETE,
- + NJS_TOKEN_PROPERTY_GETTER,
- + NJS_TOKEN_PROPERTY_SETTER,
- NJS_TOKEN_ARRAY,
- diff --git a/src/njs_lexer_keyword.c b/src/njs_lexer_keyword.c
- --- a/src/njs_lexer_keyword.c
- +++ b/src/njs_lexer_keyword.c
- @@ -186,6 +186,8 @@ njs_lexer_keyword(njs_lexer_t *lexer, nj
- lhq.key = lt->text;
- lhq.proto = &njs_keyword_hash_proto;
- + lexer->keyword = 0;
- +
- if (njs_lvlhsh_find(&lexer->keywords_hash, &lhq) == NJS_OK) {
- keyword = lhq.value;
- lt->token = keyword->token;
- diff --git a/src/njs_object.c b/src/njs_object.c
- --- a/src/njs_object.c
- +++ b/src/njs_object.c
- @@ -1112,7 +1112,8 @@ njs_object_define_property(njs_vm_t *vm,
- name = njs_arg(args, nargs, 2);
- - ret = njs_object_prop_define(vm, value, name, desc);
- + ret = njs_object_prop_define(vm, value, name,
- + NJS_OBJECT_PROP_DESCRIPTOR, desc);
- if (njs_slow_path(ret != NJS_OK)) {
- return NJS_ERROR;
- }
- @@ -1165,7 +1166,9 @@ njs_object_define_properties(njs_vm_t *v
- }
- if (prop->enumerable && njs_is_object(&prop->value)) {
- - ret = njs_object_prop_define(vm, value, &prop->name, &prop->value);
- + ret = njs_object_prop_define(vm, value, &prop->name,
- + NJS_OBJECT_PROP_DESCRIPTOR,
- + &prop->value);
- if (njs_slow_path(ret != NJS_OK)) {
- return NJS_ERROR;
- diff --git a/src/njs_object.h b/src/njs_object.h
- --- a/src/njs_object.h
- +++ b/src/njs_object.h
- @@ -8,6 +8,11 @@
- #define _NJS_OBJECT_H_INCLUDED_
- +#define NJS_OBJECT_PROP_DESCRIPTOR 0
- +#define NJS_OBJECT_PROP_GETTER 1
- +#define NJS_OBJECT_PROP_SETTER 2
- +
- +
- #define njs_is_data_descriptor(prop) \
- ((prop)->writable != NJS_ATTRIBUTE_UNSET || njs_is_valid(&(prop)->value))
- @@ -68,7 +73,7 @@ njs_object_prop_t *njs_object_prop_alloc
- njs_int_t njs_object_property(njs_vm_t *vm, const njs_value_t *value,
- njs_lvlhsh_query_t *lhq, njs_value_t *retval);
- njs_int_t njs_object_prop_define(njs_vm_t *vm, njs_value_t *object,
- - njs_value_t *name, njs_value_t *value);
- + njs_value_t *name, uint8_t type, njs_value_t *value);
- njs_int_t njs_object_prop_descriptor(njs_vm_t *vm, njs_value_t *dest,
- njs_value_t *value, njs_value_t *setval);
- const char *njs_prop_type_string(njs_object_prop_type_t type);
- diff --git a/src/njs_object_prop.c b/src/njs_object_prop.c
- --- a/src/njs_object_prop.c
- +++ b/src/njs_object_prop.c
- @@ -8,8 +8,8 @@
- #include <njs_main.h>
- -static njs_object_prop_t *njs_descriptor_prop(njs_vm_t *vm,
- - const njs_value_t *name, const njs_value_t *desc);
- +static njs_int_t njs_descriptor_prop(njs_vm_t *vm,
- + njs_object_prop_t *prop, const njs_value_t *desc);
- njs_object_prop_t *
- @@ -102,7 +102,7 @@ found:
- */
- njs_int_t
- njs_object_prop_define(njs_vm_t *vm, njs_value_t *object,
- - njs_value_t *name, njs_value_t *value)
- + njs_value_t *name, uint8_t type, njs_value_t *value)
- {
- njs_int_t ret;
- njs_object_prop_t *prop, *prev;
- @@ -116,11 +116,38 @@ njs_object_prop_define(njs_vm_t *vm, njs
- return ret;
- }
- - prop = njs_descriptor_prop(vm, name, value);
- + prop = njs_object_prop_alloc(vm, name, &njs_value_invalid,
- + NJS_ATTRIBUTE_UNSET);
- if (njs_slow_path(prop == NULL)) {
- return NJS_ERROR;
- }
- + switch (type) {
- +
- + case NJS_OBJECT_PROP_DESCRIPTOR:
- + if (njs_descriptor_prop(vm, prop, value) != NJS_OK) {
- + return NJS_ERROR;
- + }
- +
- + break;
- +
- + case NJS_OBJECT_PROP_GETTER:
- + prop->getter = *value;
- + prop->setter = njs_value_invalid;
- + prop->enumerable = NJS_ATTRIBUTE_TRUE;
- + prop->configurable = NJS_ATTRIBUTE_TRUE;
- +
- + break;
- +
- + case NJS_OBJECT_PROP_SETTER:
- + prop->setter = *value;
- + prop->getter = njs_value_invalid;
- + prop->enumerable = NJS_ATTRIBUTE_TRUE;
- + prop->configurable = NJS_ATTRIBUTE_TRUE;
- +
- + break;
- + }
- +
- if (njs_fast_path(ret == NJS_DECLINED)) {
- /* 6.2.5.6 CompletePropertypropriptor */
- @@ -332,37 +359,30 @@ exception:
- }
- -static njs_object_prop_t *
- -njs_descriptor_prop(njs_vm_t *vm, const njs_value_t *name,
- +static njs_int_t
- +njs_descriptor_prop(njs_vm_t *vm, njs_object_prop_t *prop,
- const njs_value_t *desc)
- {
- njs_int_t ret;
- njs_bool_t data, accessor;
- njs_value_t value;
- - njs_object_prop_t *prop;
- njs_lvlhsh_query_t lhq;
- data = 0;
- accessor = 0;
- - prop = njs_object_prop_alloc(vm, name, &njs_value_invalid,
- - NJS_ATTRIBUTE_UNSET);
- - if (njs_slow_path(prop == NULL)) {
- - return NULL;
- - }
- -
- njs_object_property_init(&lhq, "get", NJS_GET_HASH);
- ret = njs_object_property(vm, desc, &lhq, &value);
- if (njs_slow_path(ret == NJS_ERROR)) {
- - return NULL;
- + return NJS_ERROR;
- }
- if (ret == NJS_OK) {
- if (njs_is_defined(&value) && !njs_is_function(&value)) {
- njs_type_error(vm, "Getter must be a function");
- - return NULL;
- + return NJS_ERROR;
- }
- accessor = 1;
- @@ -379,13 +399,13 @@ njs_descriptor_prop(njs_vm_t *vm, const
- ret = njs_object_property(vm, desc, &lhq, &value);
- if (njs_slow_path(ret == NJS_ERROR)) {
- - return NULL;
- + return ret;
- }
- if (ret == NJS_OK) {
- if (njs_is_defined(&value) && !njs_is_function(&value)) {
- njs_type_error(vm, "Setter must be a function");
- - return NULL;
- + return NJS_ERROR;
- }
- accessor = 1;
- @@ -402,7 +422,7 @@ njs_descriptor_prop(njs_vm_t *vm, const
- ret = njs_object_property(vm, desc, &lhq, &value);
- if (njs_slow_path(ret == NJS_ERROR)) {
- - return NULL;
- + return ret;
- }
- if (ret == NJS_OK) {
- @@ -416,7 +436,7 @@ njs_descriptor_prop(njs_vm_t *vm, const
- ret = njs_object_property(vm, desc, &lhq, &value);
- if (njs_slow_path(ret == NJS_ERROR)) {
- - return NULL;
- + return ret;
- }
- if (ret == NJS_OK) {
- @@ -430,7 +450,7 @@ njs_descriptor_prop(njs_vm_t *vm, const
- ret = njs_object_property(vm, desc, &lhq, &value);
- if (njs_slow_path(ret == NJS_ERROR)) {
- - return NULL;
- + return ret;
- }
- if (ret == NJS_OK) {
- @@ -443,7 +463,7 @@ njs_descriptor_prop(njs_vm_t *vm, const
- ret = njs_object_property(vm, desc, &lhq, &value);
- if (njs_slow_path(ret == NJS_ERROR)) {
- - return NULL;
- + return ret;
- }
- if (ret == NJS_OK) {
- @@ -453,10 +473,10 @@ njs_descriptor_prop(njs_vm_t *vm, const
- if (accessor && data) {
- njs_type_error(vm, "Cannot both specify accessors "
- "and a value or writable attribute");
- - return NULL;
- + return NJS_ERROR;
- }
- - return prop;
- + return NJS_OK;
- }
- diff --git a/src/njs_parser_terminal.c b/src/njs_parser_terminal.c
- --- a/src/njs_parser_terminal.c
- +++ b/src/njs_parser_terminal.c
- @@ -19,6 +19,10 @@ static njs_token_t njs_parser_object(njs
- static njs_int_t njs_parser_object_property(njs_vm_t *vm, njs_parser_t *parser,
- njs_parser_node_t *parent, njs_parser_node_t *property,
- njs_parser_node_t *value);
- +static njs_int_t njs_parser_property_accessor(njs_vm_t *vm,
- + njs_parser_t *parser, njs_parser_node_t *parent,
- + njs_parser_node_t *property, njs_parser_node_t *value,
- + njs_token_t accessor);
- static njs_token_t njs_parser_array(njs_vm_t *vm, njs_parser_t *parser,
- njs_parser_node_t *array);
- static njs_int_t njs_parser_array_item(njs_vm_t *vm, njs_parser_t *parser,
- @@ -482,16 +486,17 @@ njs_parser_object(njs_vm_t *vm, njs_pars
- uint32_t hash, token_line;
- njs_int_t ret;
- njs_str_t name;
- - njs_token_t token, prop_token;
- + njs_token_t token, accessor;
- njs_lexer_t *lexer;
- njs_parser_node_t *object, *property, *expression;
- njs_function_lambda_t *lambda;
- lexer = parser->lexer;
- - /* GCC and Clang complain about uninitialized hash. */
- + /* GCC and Clang complain about uninitialized values. */
- hash = 0;
- token_line = 0;
- + property = NULL;
- object = njs_parser_node_new(vm, parser, NJS_TOKEN_OBJECT_VALUE);
- if (njs_slow_path(object == NULL)) {
- @@ -501,16 +506,46 @@ njs_parser_object(njs_vm_t *vm, njs_pars
- object->u.object = obj;
- for ( ;; ) {
- - prop_token = njs_parser_token(vm, parser);
- - if (njs_slow_path(prop_token <= NJS_TOKEN_ILLEGAL)) {
- - return prop_token;
- + token = njs_parser_token(vm, parser);
- + if (njs_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
- + return token;
- }
- + accessor = 0;
- njs_memzero(&name, sizeof(njs_str_t));
- - switch (prop_token) {
- + if (token == NJS_TOKEN_NAME || lexer->keyword) {
- + name = *njs_parser_text(parser);
- + hash = njs_parser_key_hash(parser);
- + token_line = njs_parser_token_line(parser);
- +
- + property = njs_parser_node_string(vm, parser);
- + if (njs_slow_path(property == NULL)) {
- + return NJS_TOKEN_ERROR;
- + }
- +
- + if (token == NJS_TOKEN_NAME && name.length == 3
- + && (memcmp(name.start, "get", 3) == 0
- + || memcmp(name.start, "set", 3) == 0))
- + {
- + accessor = (name.start[0] == 'g') ? NJS_TOKEN_PROPERTY_GETTER
- + : NJS_TOKEN_PROPERTY_SETTER;
- +
- + token = njs_parser_token(vm, parser);
- + if (njs_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
- + return token;
- + }
- + }
- + }
- +
- + switch (token) {
- case NJS_TOKEN_CLOSE_BRACE:
- + if (accessor) {
- + accessor = 0;
- + break;
- + }
- +
- goto done;
- case NJS_TOKEN_OPEN_BRACKET:
- @@ -530,13 +565,14 @@ njs_parser_object(njs_vm_t *vm, njs_pars
- property = parser->node;
- - token = njs_parser_match(vm, parser, token, NJS_TOKEN_CLOSE_BRACKET);
- + token = njs_parser_match(vm, parser, token,
- + NJS_TOKEN_CLOSE_BRACKET);
- break;
- case NJS_TOKEN_NUMBER:
- case NJS_TOKEN_STRING:
- case NJS_TOKEN_ESCAPE_STRING:
- - token = njs_parser_terminal(vm, parser, prop_token);
- + token = njs_parser_terminal(vm, parser, token);
- if (njs_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
- return token;
- }
- @@ -545,58 +581,27 @@ njs_parser_object(njs_vm_t *vm, njs_pars
- break;
- default:
- - if (prop_token != NJS_TOKEN_NAME && !lexer->keyword) {
- - return NJS_TOKEN_ILLEGAL;
- + if (token != NJS_TOKEN_NAME && !lexer->keyword) {
- + if (name.length == 0) {
- + return NJS_TOKEN_ILLEGAL;
- + }
- +
- + accessor = 0;
- + break;
- }
- - property = njs_parser_node_string(vm, parser);
- - if (njs_slow_path(property == NULL)) {
- - return NJS_TOKEN_ERROR;
- + if (accessor) {
- + property = njs_parser_node_string(vm, parser);
- + if (njs_slow_path(property == NULL)) {
- + return NJS_TOKEN_ERROR;
- + }
- }
- - name = *njs_parser_text(parser);
- - hash = njs_parser_key_hash(parser);
- - token_line = njs_parser_token_line(parser);
- -
- token = njs_parser_token(vm, parser);
- break;
- }
- - switch (token) {
- -
- - case NJS_TOKEN_COMMA:
- - case NJS_TOKEN_CLOSE_BRACE:
- -
- - if (name.length == 0
- - || prop_token == NJS_TOKEN_THIS
- - || prop_token == NJS_TOKEN_GLOBAL_THIS)
- - {
- - return NJS_TOKEN_ILLEGAL;
- - }
- -
- - expression = njs_parser_reference(vm, parser, prop_token, &name,
- - hash, token_line);
- - if (njs_slow_path(expression == NULL)) {
- - return NJS_TOKEN_ERROR;
- - }
- -
- - break;
- -
- - case NJS_TOKEN_COLON:
- - token = njs_parser_token(vm, parser);
- - if (njs_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
- - return token;
- - }
- -
- - token = njs_parser_assignment_expression(vm, parser, token);
- - if (njs_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
- - return token;
- - }
- -
- - expression = parser->node;
- - break;
- -
- - case NJS_TOKEN_OPEN_PARENTHESIS:
- + if (accessor) {
- expression = njs_parser_node_new(vm, parser,
- NJS_TOKEN_FUNCTION_EXPRESSION);
- if (njs_slow_path(expression == NULL)) {
- @@ -606,7 +611,7 @@ njs_parser_object(njs_vm_t *vm, njs_pars
- expression->token_line = njs_parser_token_line(parser);
- parser->node = expression;
- - lambda = njs_function_lambda_alloc(vm, 0);
- + lambda = njs_mp_zalloc(vm->mem_pool, sizeof(njs_function_lambda_t));
- if (njs_slow_path(lambda == NULL)) {
- return NJS_TOKEN_ERROR;
- }
- @@ -618,15 +623,95 @@ njs_parser_object(njs_vm_t *vm, njs_pars
- return token;
- }
- - break;
- + if (accessor == NJS_TOKEN_PROPERTY_GETTER) {
- + if (lambda->nargs != 0) {
- + njs_parser_syntax_error(vm, parser,
- + "Getter must not have any formal parameters");
- + return NJS_TOKEN_ILLEGAL;
- + }
- - default:
- - return NJS_TOKEN_ILLEGAL;
- - }
- + } else {
- + if (lambda->nargs != 1) {
- + njs_parser_syntax_error(vm, parser,
- + "Setter must have exactly one formal parameter");
- + return NJS_TOKEN_ILLEGAL;
- + }
- + }
- - ret = njs_parser_object_property(vm, parser, obj, property, expression);
- - if (njs_slow_path(ret != NJS_OK)) {
- - return NJS_TOKEN_ERROR;
- + ret = njs_parser_property_accessor(vm, parser, obj, property,
- + expression, accessor);
- + if (njs_slow_path(ret != NJS_OK)) {
- + return NJS_TOKEN_ERROR;
- + }
- +
- + } else {
- + switch (token) {
- +
- + case NJS_TOKEN_COMMA:
- + case NJS_TOKEN_CLOSE_BRACE:
- +
- + if (name.length == 0
- + || lexer->prev_token == NJS_TOKEN_THIS
- + || lexer->prev_token == NJS_TOKEN_GLOBAL_THIS)
- + {
- + return NJS_TOKEN_ILLEGAL;
- + }
- +
- + expression = njs_parser_reference(vm, parser, lexer->prev_token,
- + &name, hash, token_line);
- + if (njs_slow_path(expression == NULL)) {
- + return NJS_TOKEN_ERROR;
- + }
- +
- + break;
- +
- + case NJS_TOKEN_COLON:
- + token = njs_parser_token(vm, parser);
- + if (njs_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
- + return token;
- + }
- +
- + token = njs_parser_assignment_expression(vm, parser, token);
- + if (njs_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
- + return token;
- + }
- +
- + expression = parser->node;
- + break;
- +
- + case NJS_TOKEN_OPEN_PARENTHESIS:
- + expression = njs_parser_node_new(vm, parser,
- + NJS_TOKEN_FUNCTION_EXPRESSION);
- + if (njs_slow_path(expression == NULL)) {
- + return NJS_TOKEN_ERROR;
- + }
- +
- + expression->token_line = njs_parser_token_line(parser);
- + parser->node = expression;
- +
- + lambda = njs_function_lambda_alloc(vm, 0);
- + if (njs_slow_path(lambda == NULL)) {
- + return NJS_TOKEN_ERROR;
- + }
- +
- + expression->u.value.data.u.lambda = lambda;
- +
- + token = njs_parser_function_lambda(vm, parser, lambda, token);
- + if (njs_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
- + return token;
- + }
- +
- + break;
- +
- + default:
- + return NJS_TOKEN_ILLEGAL;
- + }
- +
- + ret = njs_parser_object_property(vm, parser, obj, property,
- + expression);
- + if (njs_slow_path(ret != NJS_OK)) {
- + return NJS_TOKEN_ERROR;
- + }
- }
- if (token == NJS_TOKEN_CLOSE_BRACE) {
- @@ -690,6 +775,49 @@ njs_parser_object_property(njs_vm_t *vm,
- }
- +static njs_int_t
- +njs_parser_property_accessor(njs_vm_t *vm, njs_parser_t *parser,
- + njs_parser_node_t *parent, njs_parser_node_t *property,
- + njs_parser_node_t *value, njs_token_t accessor)
- +{
- + njs_parser_node_t *node, *stmt, *object, *propref;
- +
- + object = njs_parser_node_new(vm, parser, NJS_TOKEN_OBJECT_VALUE);
- + if (njs_slow_path(object == NULL)) {
- + return NJS_TOKEN_ERROR;
- + }
- +
- + object->u.object = parent;
- +
- + propref = njs_parser_node_new(vm, parser, 0);
- + if (njs_slow_path(propref == NULL)) {
- + return NJS_ERROR;
- + }
- +
- + propref->left = object;
- + propref->right = property;
- +
- + node = njs_parser_node_new(vm, parser, accessor);
- + if (njs_slow_path(node == NULL)) {
- + return NJS_ERROR;
- + }
- +
- + node->left = propref;
- + node->right = value;
- +
- + stmt = njs_parser_node_new(vm, parser, NJS_TOKEN_STATEMENT);
- + if (njs_slow_path(stmt == NULL)) {
- + return NJS_ERROR;
- + }
- +
- + stmt->right = node;
- + stmt->left = parent->left;
- + parent->left = stmt;
- +
- + return NJS_OK;
- +}
- +
- +
- static njs_token_t
- njs_parser_array(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *array)
- {
- diff --git a/src/njs_vmcode.c b/src/njs_vmcode.c
- --- a/src/njs_vmcode.c
- +++ b/src/njs_vmcode.c
- @@ -86,9 +86,10 @@ njs_vmcode_interpreter(njs_vm_t *vm, u_c
- njs_str_t string;
- njs_uint_t hint;
- njs_bool_t valid, lambda_call;
- - njs_value_t *retval, *value1, *value2, *src, *s1, *s2;
- - njs_value_t numeric1, numeric2, primitive1, primitive2,
- - dst;
- + njs_value_t *retval, *value1, *value2;
- + njs_value_t *src, *s1, *s2, dst;
- + njs_value_t *function, name;
- + njs_value_t numeric1, numeric2, primitive1, primitive2;
- njs_frame_t *frame;
- njs_jump_off_t ret;
- njs_vmcode_this_t *this;
- @@ -103,6 +104,7 @@ njs_vmcode_interpreter(njs_vm_t *vm, u_c
- njs_vmcode_equal_jump_t *equal;
- njs_vmcode_try_return_t *try_return;
- njs_vmcode_method_frame_t *method_frame;
- + njs_vmcode_prop_accessor_t *accessor;
- njs_vmcode_function_frame_t *function_frame;
- next:
- @@ -599,6 +601,27 @@ next:
- ret = sizeof(njs_vmcode_prop_set_t);
- break;
- + case NJS_VMCODE_PROPERTY_ACCESSOR:
- + accessor = (njs_vmcode_prop_accessor_t *) pc;
- + function = njs_vmcode_operand(vm, accessor->value);
- +
- + ret = njs_value_to_string(vm, &name, value2);
- + if (njs_slow_path(ret != NJS_OK)) {
- + njs_internal_error(vm, "failed conversion of type \"%s\" "
- + "to string while property define",
- + njs_type_string(value2->type));
- + return NJS_ERROR;
- + }
- +
- + ret = njs_object_prop_define(vm, value1, &name, accessor->type,
- + function);
- + if (njs_slow_path(ret != NJS_OK)) {
- + return NJS_ERROR;
- + }
- +
- + ret = sizeof(njs_vmcode_prop_accessor_t);
- + break;
- +
- case NJS_VMCODE_IF_TRUE_JUMP:
- case NJS_VMCODE_IF_FALSE_JUMP:
- ret = njs_is_true(value1);
- diff --git a/src/njs_vmcode.h b/src/njs_vmcode.h
- --- a/src/njs_vmcode.h
- +++ b/src/njs_vmcode.h
- @@ -40,6 +40,7 @@ typedef uint8_t
- #define NJS_VMCODE_STOP VMCODE0(0)
- #define NJS_VMCODE_JUMP VMCODE0(1)
- #define NJS_VMCODE_PROPERTY_SET VMCODE0(2)
- +#define NJS_VMCODE_PROPERTY_ACCESSOR VMCODE0(3)
- #define NJS_VMCODE_IF_TRUE_JUMP VMCODE0(4)
- #define NJS_VMCODE_IF_FALSE_JUMP VMCODE0(5)
- #define NJS_VMCODE_IF_EQUAL_JUMP VMCODE0(6)
- @@ -261,6 +262,15 @@ typedef struct {
- typedef struct {
- njs_vmcode_t code;
- + njs_index_t value;
- + njs_index_t object;
- + njs_index_t property;
- + uint8_t type;
- +} njs_vmcode_prop_accessor_t;
- +
- +
- +typedef struct {
- + njs_vmcode_t code;
- njs_index_t next;
- njs_index_t object;
- njs_jump_off_t offset;
- diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c
- --- a/src/test/njs_unit_test.c
- +++ b/src/test/njs_unit_test.c
- @@ -10096,6 +10096,58 @@ static njs_unit_test_t njs_test[] =
- "JSON.stringify(Object.getOwnPropertyDescriptor(o, 'a')).set"),
- njs_str("undefined") },
- + { njs_str("var get = 'get'; var o = { get }; o.get"),
- + njs_str("get") },
- +
- + { njs_str("var o = { get foo() { return 'bar'; } }; o.foo"),
- + njs_str("bar") },
- +
- + { njs_str("var o = { get lazy() { delete this.lazy; return this.lazy = Math.pow(2,3)} };o.lazy"),
- + njs_str("8") },
- +
- + { njs_str("var o = { get lazy() { delete this.lazy; return this.lazy = Math.pow(2,3)} }; o.lazy;"
- + "Object.getOwnPropertyDescriptor(o, 'lazy').value"),
- + njs_str("8") },
- +
- + { njs_str("var o = { get get() { return 'bar'; } }; o.get"),
- + njs_str("bar") },
- +
- + { njs_str("var expr = 'foo'; var o = { get [expr]() { return 'bar'; } }; o.foo"),
- + njs_str("bar") },
- +
- + { njs_str("var o = { get [{toString(){return 'get'}}]() { return 'bar'; } }; o.get"),
- + njs_str("bar") },
- +
- + { njs_str("var o = { get [{toString(){return {} }}]() { return 'bar'; } }; o.get"),
- + njs_str("InternalError: failed conversion of type \"object\" to string while property define") },
- +
- + { njs_str("var o = { get foo(v1, v2) { return 'bar'; } }; o.foo"),
- + njs_str("SyntaxError: Getter must not have any formal parameters in 1") },
- +
- + { njs_str("var o = { baz: 'bar', set foo(v) { this.baz = v; } }; o.foo = 'baz'; o.baz"),
- + njs_str("baz") },
- +
- + { njs_str("var o = { baz: 'bar', set set(v) { this.baz = v; } }; o.set = 'baz'; o.baz"),
- + njs_str("baz") },
- +
- + { njs_str("var expr = 'foo'; var o = { baz: 'bar', set [expr](v) { this.baz = v; } }; o.foo = 'baz'; o.baz"),
- + njs_str("baz") },
- +
- + { njs_str("var o = { baz: 'bar', set foo(v1, v2) { this.baz = v; } }; o.foo = 'baz'; o.baz"),
- + njs_str("SyntaxError: Setter must have exactly one formal parameter in 1") },
- +
- + { njs_str("var o = { get foo() { return 'bar'; }, set foo(v) { this.baz = v; } }; o.foo"),
- + njs_str("bar") },
- +
- + { njs_str("var expr = 'foo'; var o = { get [expr]() { return 'bar'; }, set [expr](v) { this.baz = v; } }; o.foo"),
- + njs_str("bar") },
- +
- + { njs_str("Object.getOwnPropertyDescriptor({get foo() {}}, 'foo').enumerable"),
- + njs_str("true") },
- +
- + { njs_str("Object.getOwnPropertyDescriptor({get foo() {}}, 'foo').configurable"),
- + njs_str("true") },
- +
- { njs_str("var p = { a:5 }; var o = Object.create(p);"
- "Object.getPrototypeOf(o) === p"),
- njs_str("true") },
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement