Created
February 11, 2019 14:11
-
-
Save xeioex/6240f1300ca4e62b7c55651280beb8c3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # HG changeset patch | |
| # User hongzhidao <[email protected]> | |
| # Date 1549700768 -28800 | |
| # Sat Feb 09 16:26:08 2019 +0800 | |
| # Node ID 08285ce7dd7c372869a29e317109235045028a90 | |
| # Parent 4e8940c1bef19a4b0a4e6d5206b3884f42739126 | |
| Improved njs_parser_property_token(). | |
| diff --git a/njs/njs_parser.c b/njs/njs_parser.c | |
| --- a/njs/njs_parser.c | |
| +++ b/njs/njs_parser.c | |
| @@ -60,6 +60,7 @@ static njs_token_t njs_parser_object(njs | |
| njs_parser_node_t *obj); | |
| static njs_token_t njs_parser_array(njs_vm_t *vm, njs_parser_t *parser, | |
| njs_parser_node_t *obj); | |
| +static nxt_int_t njs_parser_string_create(njs_vm_t *vm, njs_value_t *value); | |
| static njs_token_t njs_parser_escape_string_create(njs_vm_t *vm, | |
| njs_parser_t *parser, njs_value_t *value); | |
| static njs_token_t njs_parser_unexpected_token(njs_vm_t *vm, | |
| @@ -1756,9 +1757,11 @@ njs_parser_grouping_expression(njs_vm_t | |
| njs_token_t | |
| -njs_parser_property_token(njs_parser_t *parser) | |
| +njs_parser_property_token(njs_vm_t *vm, njs_parser_t *parser) | |
| { | |
| - njs_token_t token; | |
| + nxt_int_t ret; | |
| + njs_token_t token; | |
| + njs_parser_node_t *node; | |
| parser->lexer->property = 1; | |
| @@ -1766,6 +1769,20 @@ njs_parser_property_token(njs_parser_t * | |
| parser->lexer->property = 0; | |
| + if (token == NJS_TOKEN_NAME) { | |
| + node = njs_parser_node_new(vm, parser, NJS_TOKEN_STRING); | |
| + if (nxt_slow_path(node == NULL)) { | |
| + return NJS_TOKEN_ERROR; | |
| + } | |
| + | |
| + ret = njs_parser_string_create(vm, &node->u.value); | |
| + if (nxt_slow_path(ret != NXT_OK)) { | |
| + return NJS_TOKEN_ERROR; | |
| + } | |
| + | |
| + parser->node = node; | |
| + } | |
| + | |
| return token; | |
| } | |
| @@ -2183,7 +2200,7 @@ njs_parser_object(njs_vm_t *vm, njs_pars | |
| object->u.object = obj; | |
| for ( ;; ) { | |
| - token = njs_parser_property_token(parser); | |
| + token = njs_parser_property_token(vm, parser); | |
| switch (token) { | |
| @@ -2191,7 +2208,7 @@ njs_parser_object(njs_vm_t *vm, njs_pars | |
| return njs_parser_token(parser); | |
| case NJS_TOKEN_NAME: | |
| - token = njs_parser_property_name(vm, parser); | |
| + token = njs_parser_token(parser); | |
| break; | |
| case NJS_TOKEN_NUMBER: | |
| @@ -2351,7 +2368,7 @@ njs_parser_array(njs_vm_t *vm, njs_parse | |
| } | |
| -nxt_int_t | |
| +static nxt_int_t | |
| njs_parser_string_create(njs_vm_t *vm, njs_value_t *value) | |
| { | |
| u_char *p; | |
| diff --git a/njs/njs_parser.h b/njs/njs_parser.h | |
| --- a/njs/njs_parser.h | |
| +++ b/njs/njs_parser.h | |
| @@ -320,10 +320,8 @@ njs_token_t njs_parser_assignment_expres | |
| njs_parser_t *parser, njs_token_t token); | |
| njs_token_t njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, | |
| njs_token_t token); | |
| -njs_token_t njs_parser_property_name(njs_vm_t *vm, njs_parser_t *parser); | |
| -njs_token_t njs_parser_property_token(njs_parser_t *parser); | |
| +njs_token_t njs_parser_property_token(njs_vm_t *vm, njs_parser_t *parser); | |
| njs_token_t njs_parser_token(njs_parser_t *parser); | |
| -nxt_int_t njs_parser_string_create(njs_vm_t *vm, njs_value_t *value); | |
| njs_variable_t *njs_variable_resolve(njs_vm_t *vm, njs_parser_node_t *node); | |
| njs_index_t njs_variable_typeof(njs_vm_t *vm, njs_parser_node_t *node); | |
| njs_index_t njs_variable_index(njs_vm_t *vm, njs_parser_node_t *node); | |
| diff --git a/njs/njs_parser_expression.c b/njs/njs_parser_expression.c | |
| --- a/njs/njs_parser_expression.c | |
| +++ b/njs/njs_parser_expression.c | |
| @@ -984,7 +984,7 @@ njs_parser_property_expression(njs_vm_t | |
| if (token == NJS_TOKEN_DOT) { | |
| - token = njs_parser_property_token(parser); | |
| + token = njs_parser_property_token(vm, parser); | |
| if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { | |
| return token; | |
| } | |
| @@ -993,7 +993,7 @@ njs_parser_property_expression(njs_vm_t | |
| return NJS_TOKEN_ILLEGAL; | |
| } | |
| - token = njs_parser_property_name(vm, parser); | |
| + token = njs_parser_token(parser); | |
| } else { | |
| token = njs_parser_token(parser); | |
| @@ -1014,28 +1014,6 @@ njs_parser_property_expression(njs_vm_t | |
| } | |
| -njs_token_t | |
| -njs_parser_property_name(njs_vm_t *vm, njs_parser_t *parser) | |
| -{ | |
| - nxt_int_t ret; | |
| - njs_parser_node_t *node; | |
| - | |
| - node = njs_parser_node_new(vm, parser, NJS_TOKEN_STRING); | |
| - if (nxt_slow_path(node == NULL)) { | |
| - return NJS_TOKEN_ERROR; | |
| - } | |
| - | |
| - ret = njs_parser_string_create(vm, &node->u.value); | |
| - if (nxt_slow_path(ret != NXT_OK)) { | |
| - return NJS_TOKEN_ERROR; | |
| - } | |
| - | |
| - parser->node = node; | |
| - | |
| - return njs_parser_token(parser); | |
| -} | |
| - | |
| - | |
| static njs_token_t | |
| njs_parser_property_brackets(njs_vm_t *vm, njs_parser_t *parser, | |
| njs_token_t token) | |
| # HG changeset patch | |
| # User hongzhidao <[email protected]> | |
| # Date 1549704844 -28800 | |
| # Sat Feb 09 17:34:04 2019 +0800 | |
| # Node ID 64a0444aaa1a6c2688a7ba2173c5ed5c2b79c6e3 | |
| # Parent 08285ce7dd7c372869a29e317109235045028a90 | |
| Refactored njs_parser_terminal(). | |
| 1) Introduced njs_parser_reference(). | |
| 2) njs_parser_builtin_object() and njs_parser_builtin_function() | |
| are refactored into njs_parser_builtin(). | |
| 3) njs_parser_external() is simplified and renamed as | |
| njs_external_lookup(). | |
| diff --git a/njs/njs_extern.c b/njs/njs_extern.c | |
| --- a/njs/njs_extern.c | |
| +++ b/njs/njs_extern.c | |
| @@ -304,13 +304,13 @@ njs_extern_keys_array(njs_vm_t *vm, cons | |
| njs_value_t * | |
| -njs_parser_external(njs_vm_t *vm, njs_parser_t *parser) | |
| +njs_external_lookup(njs_vm_t *vm, nxt_str_t *name, uint32_t hash) | |
| { | |
| nxt_lvlhsh_query_t lhq; | |
| njs_extern_value_t *ev; | |
| - lhq.key_hash = parser->lexer->key_hash; | |
| - lhq.key = parser->lexer->text; | |
| + lhq.key_hash = hash; | |
| + lhq.key = *name; | |
| lhq.proto = &njs_extern_value_hash_proto; | |
| if (nxt_lvlhsh_find(&vm->externals_hash, &lhq) == NXT_OK) { | |
| diff --git a/njs/njs_extern.h b/njs/njs_extern.h | |
| --- a/njs/njs_extern.h | |
| +++ b/njs/njs_extern.h | |
| @@ -42,6 +42,7 @@ typedef struct { | |
| njs_array_t *njs_extern_keys_array(njs_vm_t *vm, const njs_extern_t *external); | |
| +njs_value_t *njs_external_lookup(njs_vm_t *vm, nxt_str_t *name, uint32_t hash); | |
| nxt_int_t njs_external_match_native_function(njs_vm_t *vm, | |
| njs_function_native_t func, nxt_str_t *name); | |
| diff --git a/njs/njs_parser.c b/njs/njs_parser.c | |
| --- a/njs/njs_parser.c | |
| +++ b/njs/njs_parser.c | |
| @@ -52,10 +52,9 @@ static njs_token_t njs_parser_throw_stat | |
| njs_parser_t *parser); | |
| static njs_token_t njs_parser_grouping_expression(njs_vm_t *vm, | |
| njs_parser_t *parser); | |
| -static njs_token_t njs_parser_builtin_object(njs_vm_t *vm, njs_parser_t *parser, | |
| - njs_parser_node_t *node); | |
| -static njs_token_t njs_parser_builtin_function(njs_vm_t *vm, | |
| - njs_parser_t *parser, njs_parser_node_t *node); | |
| +static nxt_int_t njs_parser_builtin(njs_vm_t *vm, njs_parser_t *parser, | |
| + njs_parser_node_t *node, njs_value_type_t type, nxt_str_t *name, | |
| + uint32_t hash); | |
| static njs_token_t njs_parser_object(njs_vm_t *vm, njs_parser_t *parser, | |
| njs_parser_node_t *obj); | |
| static njs_token_t njs_parser_array(njs_vm_t *vm, njs_parser_t *parser, | |
| @@ -1805,156 +1804,22 @@ njs_parser_token(njs_parser_t *parser) | |
| } | |
| -njs_token_t | |
| -njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) | |
| +static njs_parser_node_t * | |
| +njs_parser_reference(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token, | |
| + nxt_str_t *name, uint32_t hash) | |
| { | |
| - double num; | |
| njs_ret_t ret; | |
| njs_value_t *ext; | |
| njs_parser_node_t *node; | |
| njs_parser_scope_t *scope; | |
| - if (token == NJS_TOKEN_OPEN_PARENTHESIS) { | |
| - | |
| - token = njs_parser_token(parser); | |
| - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { | |
| - return token; | |
| - } | |
| - | |
| - token = njs_parser_expression(vm, parser, token); | |
| - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { | |
| - return token; | |
| - } | |
| - | |
| - return njs_parser_match(vm, parser, token, NJS_TOKEN_CLOSE_PARENTHESIS); | |
| - } | |
| - | |
| - if (token == NJS_TOKEN_FUNCTION) { | |
| - return njs_parser_function_expression(vm, parser); | |
| - } | |
| - | |
| node = njs_parser_node_new(vm, parser, token); | |
| if (nxt_slow_path(node == NULL)) { | |
| - return NJS_TOKEN_ERROR; | |
| + return NULL; | |
| } | |
| switch (token) { | |
| - case NJS_TOKEN_NAME: | |
| - nxt_thread_log_debug("JS: %V", &parser->lexer->text); | |
| - | |
| - ext = njs_parser_external(vm, parser); | |
| - | |
| - if (ext != NULL) { | |
| - node->token = NJS_TOKEN_EXTERNAL; | |
| - node->u.value = *ext; | |
| - node->index = (njs_index_t) ext; | |
| - break; | |
| - } | |
| - | |
| - ret = njs_parser_variable_reference(vm, parser, node, NJS_REFERENCE); | |
| - if (nxt_slow_path(ret != NXT_OK)) { | |
| - return NJS_TOKEN_ERROR; | |
| - } | |
| - | |
| - break; | |
| - | |
| - case NJS_TOKEN_OPEN_BRACE: | |
| - node->token = NJS_TOKEN_OBJECT; | |
| - | |
| - nxt_thread_log_debug("JS: OBJECT"); | |
| - | |
| - parser->node = node; | |
| - | |
| - token = njs_parser_object(vm, parser, node); | |
| - | |
| - if (parser->node != node) { | |
| - /* The object is not empty. */ | |
| - node->left = parser->node; | |
| - parser->node = node; | |
| - } | |
| - | |
| - return token; | |
| - | |
| - case NJS_TOKEN_OPEN_BRACKET: | |
| - node->token = NJS_TOKEN_ARRAY; | |
| - | |
| - nxt_thread_log_debug("JS: ARRAY"); | |
| - | |
| - parser->node = node; | |
| - | |
| - token = njs_parser_array(vm, parser, node); | |
| - | |
| - if (parser->node != node) { | |
| - /* The array is not empty. */ | |
| - node->left = parser->node; | |
| - parser->node = node; | |
| - } | |
| - | |
| - return token; | |
| - | |
| - case NJS_TOKEN_DIVISION: | |
| - token = njs_regexp_literal(vm, parser, &node->u.value); | |
| - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { | |
| - return token; | |
| - } | |
| - | |
| - nxt_thread_log_debug("REGEX: '%V'", &parser->lexer->text); | |
| - | |
| - node->token = NJS_TOKEN_REGEXP; | |
| - | |
| - break; | |
| - | |
| - case NJS_TOKEN_STRING: | |
| - nxt_thread_log_debug("JS: '%V'", &parser->lexer->text); | |
| - | |
| - ret = njs_parser_string_create(vm, &node->u.value); | |
| - if (nxt_slow_path(ret != NXT_OK)) { | |
| - return NJS_TOKEN_ERROR; | |
| - } | |
| - | |
| - break; | |
| - | |
| - case NJS_TOKEN_ESCAPE_STRING: | |
| - node->token = NJS_TOKEN_STRING; | |
| - | |
| - nxt_thread_log_debug("JS: '%V'", &parser->lexer->text); | |
| - | |
| - ret = njs_parser_escape_string_create(vm, parser, &node->u.value); | |
| - if (nxt_slow_path(ret != NJS_TOKEN_STRING)) { | |
| - return ret; | |
| - } | |
| - | |
| - break; | |
| - | |
| - case NJS_TOKEN_UNTERMINATED_STRING: | |
| - njs_parser_syntax_error(vm, parser, "Unterminated string \"%V\"", | |
| - &parser->lexer->text); | |
| - | |
| - return NJS_TOKEN_ILLEGAL; | |
| - | |
| - case NJS_TOKEN_NUMBER: | |
| - nxt_thread_log_debug("JS: %f", parser->lexer->number); | |
| - | |
| - num = parser->lexer->number; | |
| - node->u.value.data.u.number = num; | |
| - node->u.value.type = NJS_NUMBER; | |
| - node->u.value.data.truth = njs_is_number_true(num); | |
| - | |
| - break; | |
| - | |
| - case NJS_TOKEN_BOOLEAN: | |
| - nxt_thread_log_debug("JS: boolean: %V", &parser->lexer->text); | |
| - | |
| - if (parser->lexer->number == 0) { | |
| - node->u.value = njs_value_false; | |
| - | |
| - } else { | |
| - node->u.value = njs_value_true; | |
| - } | |
| - | |
| - break; | |
| - | |
| case NJS_TOKEN_NULL: | |
| nxt_thread_log_debug("JS: null"); | |
| @@ -1992,16 +1857,21 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa | |
| case NJS_TOKEN_NJS: | |
| case NJS_TOKEN_MATH: | |
| case NJS_TOKEN_JSON: | |
| - return njs_parser_builtin_object(vm, parser, node); | |
| + ret = njs_parser_builtin(vm, parser, node, NJS_OBJECT, name, hash); | |
| + if (nxt_slow_path(ret != NXT_OK)) { | |
| + return NULL; | |
| + } | |
| + | |
| + break; | |
| case NJS_TOKEN_ARGUMENTS: | |
| nxt_thread_log_debug("JS: arguments"); | |
| if (parser->scope->type <= NJS_SCOPE_GLOBAL) { | |
| njs_parser_syntax_error(vm, parser, "\"%V\" object " | |
| - "in global scope", &parser->lexer->text); | |
| - | |
| - return NJS_TOKEN_ILLEGAL; | |
| + "in global scope", name); | |
| + | |
| + return NULL; | |
| } | |
| break; | |
| @@ -2088,10 +1958,205 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa | |
| case NJS_TOKEN_SET_TIMEOUT: | |
| case NJS_TOKEN_SET_IMMEDIATE: | |
| case NJS_TOKEN_CLEAR_TIMEOUT: | |
| - return njs_parser_builtin_function(vm, parser, node); | |
| + ret = njs_parser_builtin(vm, parser, node, NJS_FUNCTION, name, hash); | |
| + if (nxt_slow_path(ret != NXT_OK)) { | |
| + return NULL; | |
| + } | |
| + | |
| + break; | |
| + | |
| + case NJS_TOKEN_NAME: | |
| + nxt_thread_log_debug("JS: %V", name); | |
| + | |
| + ext = njs_external_lookup(vm, name, hash); | |
| + | |
| + if (ext != NULL) { | |
| + node->token = NJS_TOKEN_EXTERNAL; | |
| + node->u.value = *ext; | |
| + node->index = (njs_index_t) ext; | |
| + break; | |
| + } | |
| + | |
| + ret = njs_variable_reference(vm, parser->scope, node, name, hash, | |
| + NJS_REFERENCE); | |
| + if (nxt_slow_path(ret != NXT_OK)) { | |
| + return NULL; | |
| + } | |
| + | |
| + break; | |
| default: | |
| - return njs_parser_unexpected_token(vm, parser, token); | |
| + njs_parser_unexpected_token(vm, parser, token); | |
| + return NULL; | |
| + } | |
| + | |
| + return node; | |
| +} | |
| + | |
| + | |
| +njs_token_t | |
| +njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) | |
| +{ | |
| + double num; | |
| + njs_ret_t ret; | |
| + njs_lexer_t *lexer; | |
| + njs_parser_node_t *node; | |
| + | |
| + lexer = parser->lexer; | |
| + | |
| + if (token == NJS_TOKEN_OPEN_PARENTHESIS) { | |
| + | |
| + token = njs_parser_token(parser); | |
| + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { | |
| + return token; | |
| + } | |
| + | |
| + token = njs_parser_expression(vm, parser, token); | |
| + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { | |
| + return token; | |
| + } | |
| + | |
| + return njs_parser_match(vm, parser, token, NJS_TOKEN_CLOSE_PARENTHESIS); | |
| + } | |
| + | |
| + if (token == NJS_TOKEN_FUNCTION) { | |
| + return njs_parser_function_expression(vm, parser); | |
| + } | |
| + | |
| + switch (token) { | |
| + | |
| + case NJS_TOKEN_OPEN_BRACE: | |
| + nxt_thread_log_debug("JS: OBJECT"); | |
| + | |
| + node = njs_parser_node_new(vm, parser, NJS_TOKEN_OBJECT); | |
| + if (nxt_slow_path(node == NULL)) { | |
| + return NJS_TOKEN_ERROR; | |
| + } | |
| + | |
| + parser->node = node; | |
| + | |
| + token = njs_parser_object(vm, parser, node); | |
| + | |
| + if (parser->node != node) { | |
| + /* The object is not empty. */ | |
| + node->left = parser->node; | |
| + parser->node = node; | |
| + } | |
| + | |
| + return token; | |
| + | |
| + case NJS_TOKEN_OPEN_BRACKET: | |
| + nxt_thread_log_debug("JS: ARRAY"); | |
| + | |
| + node = njs_parser_node_new(vm, parser, NJS_TOKEN_ARRAY); | |
| + if (nxt_slow_path(node == NULL)) { | |
| + return NJS_TOKEN_ERROR; | |
| + } | |
| + | |
| + parser->node = node; | |
| + | |
| + token = njs_parser_array(vm, parser, node); | |
| + | |
| + if (parser->node != node) { | |
| + /* The array is not empty. */ | |
| + node->left = parser->node; | |
| + parser->node = node; | |
| + } | |
| + | |
| + return token; | |
| + | |
| + case NJS_TOKEN_DIVISION: | |
| + node = njs_parser_node_new(vm, parser, NJS_TOKEN_REGEXP); | |
| + if (nxt_slow_path(node == NULL)) { | |
| + return NJS_TOKEN_ERROR; | |
| + } | |
| + | |
| + token = njs_regexp_literal(vm, parser, &node->u.value); | |
| + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { | |
| + return token; | |
| + } | |
| + | |
| + nxt_thread_log_debug("REGEX: '%V'", &lexer->text); | |
| + | |
| + break; | |
| + | |
| + case NJS_TOKEN_STRING: | |
| + nxt_thread_log_debug("JS: '%V'", &lexer->text); | |
| + | |
| + node = njs_parser_node_new(vm, parser, NJS_TOKEN_STRING); | |
| + if (nxt_slow_path(node == NULL)) { | |
| + return NJS_TOKEN_ERROR; | |
| + } | |
| + | |
| + ret = njs_parser_string_create(vm, &node->u.value); | |
| + if (nxt_slow_path(ret != NXT_OK)) { | |
| + return NJS_TOKEN_ERROR; | |
| + } | |
| + | |
| + break; | |
| + | |
| + case NJS_TOKEN_ESCAPE_STRING: | |
| + nxt_thread_log_debug("JS: '%V'", &lexer->text); | |
| + | |
| + node = njs_parser_node_new(vm, parser, NJS_TOKEN_STRING); | |
| + if (nxt_slow_path(node == NULL)) { | |
| + return NJS_TOKEN_ERROR; | |
| + } | |
| + | |
| + ret = njs_parser_escape_string_create(vm, parser, &node->u.value); | |
| + if (nxt_slow_path(ret != NJS_TOKEN_STRING)) { | |
| + return ret; | |
| + } | |
| + | |
| + break; | |
| + | |
| + case NJS_TOKEN_UNTERMINATED_STRING: | |
| + njs_parser_syntax_error(vm, parser, "Unterminated string \"%V\"", | |
| + &lexer->text); | |
| + | |
| + return NJS_TOKEN_ILLEGAL; | |
| + | |
| + case NJS_TOKEN_NUMBER: | |
| + num = lexer->number; | |
| + nxt_thread_log_debug("JS: %f", num); | |
| + | |
| + node = njs_parser_node_new(vm, parser, NJS_TOKEN_NUMBER); | |
| + if (nxt_slow_path(node == NULL)) { | |
| + return NJS_TOKEN_ERROR; | |
| + } | |
| + | |
| + node->u.value.data.u.number = num; | |
| + node->u.value.type = NJS_NUMBER; | |
| + node->u.value.data.truth = njs_is_number_true(num); | |
| + | |
| + break; | |
| + | |
| + case NJS_TOKEN_BOOLEAN: | |
| + nxt_thread_log_debug("JS: boolean: %V", &lexer->text); | |
| + | |
| + node = njs_parser_node_new(vm, parser, NJS_TOKEN_BOOLEAN); | |
| + if (nxt_slow_path(node == NULL)) { | |
| + return NJS_TOKEN_ERROR; | |
| + } | |
| + | |
| + if (parser->lexer->number == 0) { | |
| + node->u.value = njs_value_false; | |
| + | |
| + } else { | |
| + node->u.value = njs_value_true; | |
| + } | |
| + | |
| + break; | |
| + | |
| + default: | |
| + node = njs_parser_reference(vm, parser, token, &lexer->text, | |
| + lexer->key_hash); | |
| + | |
| + if (nxt_slow_path(node == NULL)) { | |
| + return NJS_TOKEN_ERROR; | |
| + } | |
| + | |
| + break; | |
| } | |
| parser->node = node; | |
| @@ -2100,12 +2165,10 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa | |
| } | |
| -static njs_token_t | |
| -njs_parser_builtin_object(njs_vm_t *vm, njs_parser_t *parser, | |
| - njs_parser_node_t *node) | |
| +static nxt_int_t | |
| +njs_parser_builtin(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node, | |
| + njs_value_type_t type, nxt_str_t *name, uint32_t hash) | |
| { | |
| - uint32_t hash; | |
| - nxt_str_t *name; | |
| njs_ret_t ret; | |
| nxt_uint_t index; | |
| njs_variable_t *var; | |
| @@ -2117,70 +2180,36 @@ njs_parser_builtin_object(njs_vm_t *vm, | |
| scope = scope->parent; | |
| } | |
| - hash = parser->lexer->key_hash; | |
| - name = &parser->lexer->text; | |
| - | |
| var = njs_variable_add(vm, scope, name, hash, NJS_VARIABLE_VAR); | |
| if (nxt_slow_path(var == NULL)) { | |
| - return NJS_TOKEN_ERROR; | |
| + return NXT_ERROR; | |
| } | |
| /* TODO: once */ | |
| - index = node->token - NJS_TOKEN_FIRST_OBJECT; | |
| - var->value.data.u.object = &vm->shared->objects[index]; | |
| - var->value.type = NJS_OBJECT; | |
| + switch (type) { | |
| + case NJS_OBJECT: | |
| + index = node->token - NJS_TOKEN_FIRST_OBJECT; | |
| + var->value.data.u.object = &vm->shared->objects[index]; | |
| + break; | |
| + | |
| + case NJS_FUNCTION: | |
| + index = node->token - NJS_TOKEN_FIRST_FUNCTION; | |
| + var->value.data.u.function = &vm->shared->functions[index]; | |
| + break; | |
| + | |
| + default: | |
| + return NXT_ERROR; | |
| + } | |
| + | |
| + var->value.type = type; | |
| var->value.data.truth = 1; | |
| ret = njs_variable_reference(vm, scope, node, name, hash, NJS_REFERENCE); | |
| if (nxt_slow_path(ret != NXT_OK)) { | |
| - return NJS_TOKEN_ERROR; | |
| + return NXT_ERROR; | |
| } | |
| - parser->node = node; | |
| - | |
| - return njs_parser_token(parser); | |
| -} | |
| - | |
| - | |
| -static njs_token_t | |
| -njs_parser_builtin_function(njs_vm_t *vm, njs_parser_t *parser, | |
| - njs_parser_node_t *node) | |
| -{ | |
| - uint32_t hash; | |
| - nxt_str_t *name; | |
| - njs_ret_t ret; | |
| - nxt_uint_t index; | |
| - njs_variable_t *var; | |
| - njs_parser_scope_t *scope; | |
| - | |
| - scope = parser->scope; | |
| - | |
| - while (scope->type != NJS_SCOPE_GLOBAL) { | |
| - scope = scope->parent; | |
| - } | |
| - | |
| - hash = parser->lexer->key_hash; | |
| - name = &parser->lexer->text; | |
| - | |
| - var = njs_variable_add(vm, scope, name, hash, NJS_VARIABLE_VAR); | |
| - if (nxt_slow_path(var == NULL)) { | |
| - return NJS_TOKEN_ERROR; | |
| - } | |
| - | |
| - /* TODO: once */ | |
| - index = node->token - NJS_TOKEN_FIRST_FUNCTION; | |
| - var->value.data.u.function = &vm->shared->functions[index]; | |
| - var->value.type = NJS_FUNCTION; | |
| - var->value.data.truth = 1; | |
| - | |
| - ret = njs_variable_reference(vm, scope, node, name, hash, NJS_REFERENCE); | |
| - if (nxt_slow_path(ret != NXT_OK)) { | |
| - return NJS_TOKEN_ERROR; | |
| - } | |
| - | |
| - parser->node = node; | |
| - | |
| - return njs_parser_token(parser); | |
| + return NXT_OK; | |
| } | |
| diff --git a/njs/njs_parser.h b/njs/njs_parser.h | |
| --- a/njs/njs_parser.h | |
| +++ b/njs/njs_parser.h | |
| @@ -306,8 +306,6 @@ void njs_lexer_rollback(njs_lexer_t *lex | |
| nxt_int_t njs_lexer_keywords_init(nxt_mp_t *mcp, nxt_lvlhsh_t *hash); | |
| njs_token_t njs_lexer_keyword(njs_lexer_t *lexer); | |
| -njs_value_t *njs_parser_external(njs_vm_t *vm, njs_parser_t *parser); | |
| - | |
| nxt_int_t njs_parser(njs_vm_t *vm, njs_parser_t *parser, | |
| njs_parser_t *prev); | |
| njs_token_t njs_parser_arguments(njs_vm_t *vm, njs_parser_t *parser, | |
| # HG changeset patch | |
| # User Dmitry Volyntsev <[email protected]> | |
| # Date 1549894226 -10800 | |
| # Mon Feb 11 17:10:26 2019 +0300 | |
| # Node ID f6c506126c468ee25aefc2e99aa7013e68df6bf8 | |
| # Parent 64a0444aaa1a6c2688a7ba2173c5ed5c2b79c6e3 | |
| Added support for shorthand property names for Object literals. | |
| diff --git a/njs/njs_lexer.c b/njs/njs_lexer.c | |
| --- a/njs/njs_lexer.c | |
| +++ b/njs/njs_lexer.c | |
| @@ -459,7 +459,8 @@ njs_lexer_next_token(njs_lexer_t *lexer) | |
| static njs_token_t | |
| njs_lexer_word(njs_lexer_t *lexer, u_char c) | |
| { | |
| - u_char *p; | |
| + u_char *p; | |
| + njs_token_t token; | |
| /* TODO: UTF-8 */ | |
| @@ -498,11 +499,14 @@ njs_lexer_word(njs_lexer_t *lexer, u_cha | |
| lexer->start = p; | |
| lexer->text.length = p - lexer->text.start; | |
| + token = njs_lexer_keyword(lexer); | |
| + | |
| if (lexer->property) { | |
| + lexer->property_token = token; | |
| return NJS_TOKEN_NAME; | |
| } | |
| - return njs_lexer_keyword(lexer); | |
| + return token; | |
| } | |
| diff --git a/njs/njs_parser.c b/njs/njs_parser.c | |
| --- a/njs/njs_parser.c | |
| +++ b/njs/njs_parser.c | |
| @@ -2213,13 +2213,29 @@ njs_parser_builtin(njs_vm_t *vm, njs_par | |
| } | |
| +/* | |
| + * ES6: 12.2.6 Object Initializer | |
| + * Supported syntax: | |
| + * PropertyDefinition: | |
| + * PropertyName : AssignmentExpression | |
| + * IdentifierReference | |
| + * PropertyName: | |
| + * IdentifierName, StringLiteral, NumericLiteral. | |
| + */ | |
| static njs_token_t | |
| njs_parser_object(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *obj) | |
| { | |
| + uint32_t hash; | |
| + nxt_str_t name; | |
| njs_token_t token; | |
| - njs_parser_node_t *stmt, *assign, *object, *propref, *left; | |
| + njs_lexer_t *lexer; | |
| + njs_parser_node_t *stmt, *assign, *object, *propref, *left, *expression; | |
| left = NULL; | |
| + lexer = parser->lexer; | |
| + | |
| + /* GCC and Clang complain about uninitialized hash. */ | |
| + hash = 0; | |
| object = njs_parser_node_new(vm, parser, NJS_TOKEN_OBJECT_VALUE); | |
| if (nxt_slow_path(object == NULL)) { | |
| @@ -2231,12 +2247,17 @@ njs_parser_object(njs_vm_t *vm, njs_pars | |
| for ( ;; ) { | |
| token = njs_parser_property_token(vm, parser); | |
| + name.start = NULL; | |
| + | |
| switch (token) { | |
| case NJS_TOKEN_CLOSE_BRACE: | |
| return njs_parser_token(parser); | |
| case NJS_TOKEN_NAME: | |
| + name = lexer->text; | |
| + hash = lexer->key_hash; | |
| + | |
| token = njs_parser_token(parser); | |
| break; | |
| @@ -2262,14 +2283,29 @@ njs_parser_object(njs_vm_t *vm, njs_pars | |
| propref->left = object; | |
| propref->right = parser->node; | |
| - token = njs_parser_match(vm, parser, token, NJS_TOKEN_COLON); | |
| - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { | |
| - return token; | |
| - } | |
| - | |
| - token = njs_parser_assignment_expression(vm, parser, token); | |
| - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { | |
| - return token; | |
| + if (name.start != NULL | |
| + && (token == NJS_TOKEN_COMMA || token == NJS_TOKEN_CLOSE_BRACE) | |
| + && lexer->property_token != NJS_TOKEN_THIS | |
| + && lexer->property_token != NJS_TOKEN_GLOBAL_THIS) | |
| + { | |
| + expression = njs_parser_reference(vm, parser, lexer->property_token, | |
| + &name, hash); | |
| + if (nxt_slow_path(expression == NULL)) { | |
| + return NJS_TOKEN_ERROR; | |
| + } | |
| + | |
| + } else { | |
| + token = njs_parser_match(vm, parser, token, NJS_TOKEN_COLON); | |
| + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { | |
| + return token; | |
| + } | |
| + | |
| + token = njs_parser_assignment_expression(vm, parser, token); | |
| + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { | |
| + return token; | |
| + } | |
| + | |
| + expression = parser->node; | |
| } | |
| assign = njs_parser_node_new(vm, parser, NJS_TOKEN_ASSIGNMENT); | |
| @@ -2279,7 +2315,7 @@ njs_parser_object(njs_vm_t *vm, njs_pars | |
| assign->u.operation = njs_vmcode_move; | |
| assign->left = propref; | |
| - assign->right = parser->node; | |
| + assign->right = expression; | |
| stmt = njs_parser_node_new(vm, parser, NJS_TOKEN_STATEMENT); | |
| if (nxt_slow_path(stmt == NULL)) { | |
| diff --git a/njs/njs_parser.h b/njs/njs_parser.h | |
| --- a/njs/njs_parser.h | |
| +++ b/njs/njs_parser.h | |
| @@ -210,7 +210,10 @@ typedef enum { | |
| typedef struct { | |
| njs_token_t token:16; | |
| njs_token_t prev_token:16; | |
| + | |
| uint8_t property; /* 1 bit */ | |
| + njs_token_t property_token:16; | |
| + | |
| uint32_t key_hash; | |
| uint32_t token_line; | |
| diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c | |
| --- a/njs/test/njs_unit_test.c | |
| +++ b/njs/test/njs_unit_test.c | |
| @@ -2761,6 +2761,38 @@ static njs_unit_test_t njs_test[] = | |
| { nxt_string("var x = { a: 1 }, b = delete x.a; x.a +' '+ b"), | |
| nxt_string("undefined true") }, | |
| + /* Shorthand Object literals. */ | |
| + | |
| + { nxt_string("var a = 1; njs.dump({a})"), | |
| + nxt_string("{a:1}") }, | |
| + | |
| + { nxt_string("var a = 1, b; njs.dump({a,b})"), | |
| + nxt_string("{a:1,b:undefined}") }, | |
| + | |
| + { nxt_string("var a = 1, b = 2; ({a,b,c})"), | |
| + nxt_string("ReferenceError: \"c\" is not defined in 1") }, | |
| + | |
| + { nxt_string("var a = 1, b = 2; njs.dump({a,b,c:3})"), | |
| + nxt_string("{a:1,b:2,c:3}") }, | |
| + | |
| + { nxt_string("var b = 2, c = 3; njs.dump({a:1,b,c})"), | |
| + nxt_string("{a:1,b:2,c:3}") }, | |
| + | |
| + { nxt_string("({1})"), | |
| + nxt_string("SyntaxError: Unexpected token \"}\" in 1") }, | |
| + | |
| + { nxt_string("({default})"), | |
| + nxt_string("SyntaxError: Unexpected token \"}\" in 1") }, | |
| + | |
| + { nxt_string("({var})"), | |
| + nxt_string("SyntaxError: Unexpected token \"}\" in 1") }, | |
| + | |
| + { nxt_string("({this})"), | |
| + nxt_string("SyntaxError: Unexpected token \"}\" in 1") }, | |
| + | |
| + { nxt_string("typeof ({Math}).Math.sin"), | |
| + nxt_string("function") }, | |
| + | |
| { nxt_string("delete null"), | |
| nxt_string("true") }, | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment