From f4b7c403faa8c84e580c3b548fe86a8a26c4805b Mon Sep 17 00:00:00 2001 From: Igor Sysoev Date: Tue, 15 Dec 2015 16:45:56 +0300 Subject: [PATCH] Comma expressions, statement sequences, and njs_vmcode_stop changes. --- njs/njs_generator.c | 155 ++++++++++++++++++++++++++------------- njs/njs_parser.c | 96 ++++++++++++------------ njs/test/njs_unit_test.c | 62 +++++++++++----- 3 files changed, 195 insertions(+), 118 deletions(-) diff --git a/njs/njs_generator.c b/njs/njs_generator.c index 8f9b0548..96343f63 100644 --- a/njs/njs_generator.c +++ b/njs/njs_generator.c @@ -37,6 +37,14 @@ static nxt_int_t njs_generate_for_statement(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node); static nxt_int_t njs_generate_for_in_statement(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node); +static nxt_int_t njs_generate_statement(njs_vm_t *vm, njs_parser_t *parser, + njs_parser_node_t *node); +static nxt_int_t njs_generate_children(njs_vm_t *vm, njs_parser_t *parser, + njs_parser_node_t *node); +static nxt_int_t njs_generate_stop_statement(njs_vm_t *vm, njs_parser_t *parser, + njs_parser_node_t *node); +static nxt_int_t njs_generate_comma_expression(njs_vm_t *vm, + njs_parser_t *parser, njs_parser_node_t *node); static nxt_int_t njs_generate_assignment(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node); static nxt_int_t njs_generate_operation_assignment(njs_vm_t *vm, @@ -93,7 +101,6 @@ nxt_inline nxt_bool_t njs_generator_is_constant(njs_parser_node_t *node); static nxt_int_t njs_generator(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node) { - nxt_int_t ret; njs_parser_node_t *left; if (node == NULL) { @@ -121,28 +128,13 @@ njs_generator(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node) return njs_generate_for_in_statement(vm, parser, node); case NJS_TOKEN_STATEMENT: - case NJS_TOKEN_COMMA: - - if (node->left != NULL) { - ret = njs_generator(vm, parser, node->left); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - - ret = njs_generator_node_index_release(vm, parser, node->left); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } - } - - ret = njs_generator(vm, parser, node->right); - if (nxt_slow_path(ret != NXT_OK)) { - return ret; - } + return njs_generate_statement(vm, parser, node); - node->index = node->right->index; + case NJS_TOKEN_END: + return njs_generate_stop_statement(vm, parser, node); - return njs_generator_node_index_release(vm, parser, node->right); + case NJS_TOKEN_COMMA: + return njs_generate_comma_expression(vm, parser, node); case NJS_TOKEN_ASSIGNMENT: return njs_generate_assignment(vm, parser, node); @@ -736,6 +728,91 @@ njs_generate_for_in_statement(njs_vm_t *vm, njs_parser_t *parser, } +static nxt_int_t +njs_generate_statement(njs_vm_t *vm, njs_parser_t *parser, + njs_parser_node_t *node) +{ + nxt_int_t ret; + + ret = njs_generate_children(vm, parser, node); + + if (nxt_fast_path(ret == NXT_OK)) { + return njs_generator_node_index_release(vm, parser, node->right); + } + + return ret; +} + + +static nxt_int_t +njs_generate_children(njs_vm_t *vm, njs_parser_t *parser, + njs_parser_node_t *node) +{ + nxt_int_t ret; + + ret = njs_generator(vm, parser, node->left); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + + ret = njs_generator_node_index_release(vm, parser, node->left); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + + return njs_generator(vm, parser, node->right); +} + + +static nxt_int_t +njs_generate_stop_statement(njs_vm_t *vm, njs_parser_t *parser, + njs_parser_node_t *node) +{ + nxt_int_t ret; + njs_index_t index; + njs_vmcode_stop_t *stop; + + ret = njs_generate_children(vm, parser, node); + + if (nxt_fast_path(ret == NXT_OK)) { + njs_generate_code(parser, njs_vmcode_stop_t, stop); + stop->code.operation = njs_vmcode_stop; + stop->code.operands = NJS_VMCODE_1OPERAND; + stop->code.retval = NJS_VMCODE_NO_RETVAL; + + index = NJS_INDEX_NONE; + + if (node->right != NULL) { + index = node->right->index; + } + + if (index == NJS_INDEX_NONE) { + index = njs_value_index(vm, parser, &njs_value_void); + } + + stop->retval = index; + } + + return ret; +} + + +static nxt_int_t +njs_generate_comma_expression(njs_vm_t *vm, njs_parser_t *parser, + njs_parser_node_t *node) +{ + nxt_int_t ret; + + ret = njs_generate_children(vm, parser, node); + + if (nxt_fast_path(ret == NXT_OK)) { + node->index = node->right->index; + } + + return ret; +} + + static nxt_int_t njs_generate_assignment(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node) @@ -1386,14 +1463,12 @@ njs_generate_function_scope(njs_vm_t *vm, njs_function_lambda_t *lambda, nxt_int_t njs_generate_scope(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node) { - u_char *p; - size_t code_size, size; - uintptr_t scope_size; - nxt_uint_t n; - njs_index_t index; - njs_value_t *value; - njs_vm_code_t *code; - njs_vmcode_stop_t *stop; + u_char *p; + size_t code_size, size; + uintptr_t scope_size; + nxt_uint_t n; + njs_value_t *value; + njs_vm_code_t *code; p = nxt_mem_cache_alloc(vm->mem_cache_pool, parser->code_size); if (nxt_slow_path(p == NULL)) { @@ -1403,26 +1478,8 @@ njs_generate_scope(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node) parser->code_start = p; parser->code_end = p; - if (node != NULL) { - if (nxt_slow_path(njs_generator(vm, parser, node) != NXT_OK)) { - return NXT_ERROR; - } - } - - if (parser->scope == NJS_SCOPE_GLOBAL) { - njs_generate_code(parser, njs_vmcode_stop_t, stop); - stop->code.operation = njs_vmcode_stop; - stop->code.operands = NJS_VMCODE_1OPERAND; - stop->code.retval = NJS_VMCODE_NO_RETVAL; - - if (node->index != 0) { - index = node->index; - - } else { - index = njs_value_index(vm, parser, &njs_value_void); - } - - stop->retval = index; + if (nxt_slow_path(njs_generator(vm, parser, node) != NXT_OK)) { + return NXT_ERROR; } code_size = parser->code_end - parser->code_start; diff --git a/njs/njs_parser.c b/njs/njs_parser.c index d2b407e9..f2d9216a 100644 --- a/njs/njs_parser.c +++ b/njs/njs_parser.c @@ -34,6 +34,8 @@ * is treated as a single expiression. */ +static njs_token_t njs_parser_statement_link(njs_vm_t *vm, njs_parser_t *parser, + njs_token_t token); static njs_token_t njs_parser_statement(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token); static njs_token_t njs_parser_block(njs_vm_t *vm, njs_parser_t *parser); @@ -72,63 +74,74 @@ njs_parser_node_t * njs_parser(njs_vm_t *vm, njs_parser_t *parser) { njs_token_t token; - njs_parser_node_t *node, *left; + njs_parser_node_t *node; token = njs_parser_token(parser); - if (nxt_slow_path(token <= NJS_TOKEN_END)) { + while (token != NJS_TOKEN_END) { - if (vm->exception == NULL) { - vm->exception = &njs_exception_syntax_error; + token = njs_parser_statement_link(vm, parser, token); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + return NULL; } - return NULL; - } - - left = NULL; + if (token == NJS_TOKEN_CLOSE_BRACE) { + parser->lexer->start--; - for ( ;; ) { - token = njs_parser_statement(vm, parser, token); + return parser->node; + } + } - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { + node = parser->node; - if (vm->exception == NULL) { - vm->exception = &njs_exception_syntax_error; - } + if (node == NULL) { + /* Empty string, just semicolons or variables declarations. */ - nxt_thread_log_error(NXT_LOG_ERR, "ERROR"); + node = njs_parser_node_alloc(vm); + if (nxt_slow_path(node == NULL)) { return NULL; } + } + + node->token = NJS_TOKEN_END; + + return node; +} - if (parser->node != NULL && parser->node != left) { + +static njs_token_t +njs_parser_statement_link(njs_vm_t *vm, njs_parser_t *parser, + njs_token_t token) +{ + njs_parser_node_t *node, *last; + + last = parser->node; + + token = njs_parser_statement(vm, parser, token); + + if (nxt_fast_path(token > NJS_TOKEN_ILLEGAL)) { + + if (parser->node != last) { /* * The statement is not empty block, not just semicolon, - * and not a "var" declaration without initialization. + * and not variables declaration without initialization. */ node = njs_parser_node_alloc(vm); if (nxt_slow_path(node == NULL)) { - return NULL; + return NJS_TOKEN_ERROR; } node->token = NJS_TOKEN_STATEMENT; - node->left = left; + node->left = last; node->right = parser->node; parser->node = node; - - left = node; } - if (token == NJS_TOKEN_CLOSE_BRACE) { - parser->lexer->start--; - break; - } - - if (token == NJS_TOKEN_END) { - break; - } + } else if (vm->exception == NULL) { + vm->exception = &njs_exception_syntax_error; } - return parser->node; + return token; } @@ -210,37 +223,20 @@ njs_parser_statement(njs_vm_t *vm, njs_parser_t *parser, static njs_token_t njs_parser_block(njs_vm_t *vm, njs_parser_t *parser) { - njs_token_t token; - njs_parser_node_t *node, *left; + njs_token_t token; token = njs_parser_token(parser); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } - left = NULL; + parser->node = NULL; while (token != NJS_TOKEN_CLOSE_BRACE) { - token = njs_parser_statement(vm, parser, token); + token = njs_parser_statement_link(vm, parser, token); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } - - if (parser->node != NULL) { - /* The statement is not empty block and is not just semicolon. */ - - node = njs_parser_node_alloc(vm); - if (nxt_slow_path(node == NULL)) { - return NJS_TOKEN_ERROR; - } - - node->token = NJS_TOKEN_STATEMENT; - node->left = left; - node->right = parser->node; - parser->node = node; - - left = node; - } } return njs_parser_token(parser); diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 9f652905..73b7eb8a 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -25,6 +25,40 @@ typedef struct { static njs_unit_test_t njs_test[] = { + /* Variable declarations. */ + + { nxt_string("var x"), + nxt_string("undefined") }, + + { nxt_string("var x;"), + nxt_string("undefined") }, + + { nxt_string("var x;;"), + nxt_string("undefined") }, + + { nxt_string("var x = 0"), + nxt_string("undefined") }, + + { nxt_string("var x = 0;"), + nxt_string("undefined") }, + + { nxt_string("var x = 0;;"), + nxt_string("undefined") }, + + { nxt_string("var; a"), + nxt_string("SyntaxError") }, + + { nxt_string("var \n a \n = 1; a"), + nxt_string("1") }, + + { nxt_string("var \n a, \n b; b"), + nxt_string("undefined") }, + + { nxt_string("var a = 1; var b; a"), + nxt_string("1") }, + + /* Numbers. */ + { nxt_string("999999999999999999999"), nxt_string("1e+21") }, @@ -46,10 +80,13 @@ static njs_unit_test_t njs_test[] = nxt_string("1") }, { nxt_string(""), - nxt_string("SyntaxError") }, + nxt_string("undefined") }, { nxt_string("\n"), - nxt_string("SyntaxError") }, + nxt_string("undefined") }, + + { nxt_string(";"), + nxt_string("undefined") }, { nxt_string("\n +1"), nxt_string("1") }, @@ -1284,7 +1321,7 @@ static njs_unit_test_t njs_test[] = nxt_string("SyntaxError") }, { nxt_string("var a = a + 1"), - nxt_string("NaN") }, + nxt_string("undefined") }, { nxt_string("a = b + 1; var b = 1; a +' '+ b"), nxt_string("NaN 1") }, @@ -1308,10 +1345,10 @@ static njs_unit_test_t njs_test[] = nxt_string("ReferenceError") }, { nxt_string("a += 1; var a = 2"), - nxt_string("2") }, + nxt_string("undefined") }, { nxt_string("var a = 1"), - nxt_string("1") }, + nxt_string("undefined") }, { nxt_string("var a = 1; a = (a = 2) + a"), nxt_string("4") }, @@ -1337,19 +1374,6 @@ static njs_unit_test_t njs_test[] = { nxt_string("a = 3; if (true) if (false); else; a = 2; a"), nxt_string("2") }, - /* var statements. */ - - { nxt_string("var; a"), - nxt_string("SyntaxError") }, - - { nxt_string("var \n a \n = 1; a"), - nxt_string("1") }, - - { nxt_string("var \n a, \n b; b"), - nxt_string("undefined") }, - - /**/ - { nxt_string("for (i = 0; i < 10; i++) { i += 1 } i"), nxt_string("10") }, @@ -3186,7 +3210,7 @@ static njs_unit_test_t njs_test[] = /* es5id: 8.2_A1_T2 */ { nxt_string("var x = null;"), - nxt_string("") }, + nxt_string("undefined") }, /* es5id: 8.2_A2 */ -- 2.47.3