changes.
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,
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) {
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);
}
+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)
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)) {
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;
* 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);
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;
}
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);
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") },
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") },
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") },
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") },
{ 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") },
/* es5id: 8.2_A1_T2 */
{ nxt_string("var x = null;"),
- nxt_string("") },
+ nxt_string("undefined") },
/* es5id: 8.2_A2 */