static njs_token_t njs_parser_inc_dec_expression(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) { njs_token_t next; njs_parser_node_t *node; njs_vmcode_operation_t operation; switch (token) { case NJS_TOKEN_INCREMENT: operation = njs_vmcode_increment; break; case NJS_TOKEN_DECREMENT: operation = njs_vmcode_decrement; break; default: return njs_parser_post_inc_dec_expression(vm, parser, token); } next = njs_parser_token(parser); if (nxt_slow_path(next <= NJS_TOKEN_ILLEGAL)) { return next; } next = njs_parser_call_expression(vm, parser, next); if (nxt_slow_path(next <= NJS_TOKEN_ILLEGAL)) { return next; } if (parser->node->lvalue == NJS_LVALUE_NONE) { nxt_thread_log_error(NXT_LOG_ALERT, "lvalue required"); return NJS_TOKEN_ILLEGAL; } node = njs_parser_node_alloc(vm); if (nxt_slow_path(node == NULL)) { return NJS_TOKEN_ERROR; } node->token = token; node->u.operation = operation; node->left = parser->node; parser->node = node; parser->code_size += (parser->node->token == NJS_TOKEN_NAME) ? sizeof(njs_vmcode_3addr_t): sizeof(njs_vmcode_prop_get_t) + sizeof(njs_vmcode_3addr_t) + sizeof(njs_vmcode_prop_set_t); return next; }
njs_parser_node_t * njs_nonrecursive_parser(njs_vm_t *vm, njs_parser_t *parser) { nxt_int_t ret; njs_token_t token; njs_parser_stack_operation_t operation; if (top < 0) { njs_parser_stack_push(vm, parser, njs_parser_statement); } token = njs_parser_token(parser); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { /* TODO: NJS_TOKEN_AGAIN */ return NULL; } do { operation = (njs_parser_stack_operation_t) njs_parser_stack_pop(parser); if (operation == NULL) { if (parser->lexer->token == NJS_TOKEN_END) { return parser->node; } break; } ret = operation(vm, parser, njs_parser_stack_pop(parser)); } while (ret == NXT_OK); nxt_thread_log_error(NXT_LOG_ERR, "unexpected token"); return NULL; }
static njs_token_t njs_parser_assignment_expression(njs_vm_t *vm, njs_parser_t *parser, const njs_parser_expression_t *expr, njs_token_t token) { size_t size; njs_parser_node_t *node, *pending; njs_vmcode_operation_t operation; token = njs_parser_conditional_expression(vm, parser, token); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } for ( ;; ) { switch (token) { case NJS_TOKEN_ASSIGNMENT: nxt_thread_log_debug("JS: ="); operation = njs_vmcode_move; break; case NJS_TOKEN_ADDITION_ASSIGNMENT: nxt_thread_log_debug("JS: +="); operation = njs_vmcode_addition; break; case NJS_TOKEN_SUBSTRACTION_ASSIGNMENT: nxt_thread_log_debug("JS: -="); operation = njs_vmcode_substraction; break; case NJS_TOKEN_MULTIPLICATION_ASSIGNMENT: nxt_thread_log_debug("JS: *="); operation = njs_vmcode_multiplication; break; case NJS_TOKEN_DIVISION_ASSIGNMENT: nxt_thread_log_debug("JS: /="); operation = njs_vmcode_division; break; case NJS_TOKEN_REMAINDER_ASSIGNMENT: nxt_thread_log_debug("JS: %="); operation = njs_vmcode_remainder; break; case NJS_TOKEN_LEFT_SHIFT_ASSIGNMENT: nxt_thread_log_debug("JS: <<="); operation = njs_vmcode_left_shift; break; case NJS_TOKEN_RIGHT_SHIFT_ASSIGNMENT: nxt_thread_log_debug("JS: >>="); operation = njs_vmcode_right_shift; break; case NJS_TOKEN_UNSIGNED_RIGHT_SHIFT_ASSIGNMENT: nxt_thread_log_debug("JS: >>="); operation = njs_vmcode_unsigned_right_shift; break; case NJS_TOKEN_BITWISE_AND_ASSIGNMENT: nxt_thread_log_debug("JS: &="); operation = njs_vmcode_bitwise_and; break; case NJS_TOKEN_BITWISE_XOR_ASSIGNMENT: nxt_thread_log_debug("JS: ^="); operation = njs_vmcode_bitwise_xor; break; case NJS_TOKEN_BITWISE_OR_ASSIGNMENT: nxt_thread_log_debug("JS: |="); operation = njs_vmcode_bitwise_or; break; case NJS_TOKEN_LINE_END: token = njs_lexer_token(parser->lexer); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } if (njs_parser_expression_operator(token)) { continue; } /* Fall through. */ default: return token; } node = parser->node; if (node->lvalue == NJS_LVALUE_NONE) { nxt_thread_log_error(NXT_LOG_ALERT, "lvalue required"); return NJS_TOKEN_ILLEGAL; } pending = NULL; if (node->token == NJS_TOKEN_NAME) { if (token == NJS_TOKEN_ASSIGNMENT) { node->state = NJS_VARIABLE_ASSIGNMENT; if (node->u.variable->state == NJS_VARIABLE_PENDING) { pending = node; } } else if (node->u.variable->state == NJS_VARIABLE_PENDING) { node->u.variable->state = NJS_VARIABLE_USED; } } node = njs_parser_node_alloc(vm); if (nxt_slow_path(node == NULL)) { return NJS_TOKEN_ERROR; } node->token = token; node->u.operation = operation; node->left = parser->node; token = njs_parser_token(parser); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } token = njs_parser_assignment_expression(vm, parser, NULL, token); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } node->right = parser->node; parser->node = node; if (node->left->token == NJS_TOKEN_NAME) { if (node->token == NJS_TOKEN_ASSIGNMENT) { size = sizeof(njs_vmcode_move_t); } else { if (njs_parser_has_side_effect(node->right)) { size = sizeof(njs_vmcode_move_t) + sizeof(njs_vmcode_3addr_t); } else { size = sizeof(njs_vmcode_3addr_t); } } } else { if (node->token == NJS_TOKEN_ASSIGNMENT) { size = sizeof(njs_vmcode_prop_set_t); if (njs_parser_has_side_effect(node->right)) { size += 2 * sizeof(njs_vmcode_move_t); } } else { size = sizeof(njs_vmcode_prop_get_t) + sizeof(njs_vmcode_3addr_t) + sizeof(njs_vmcode_prop_set_t); } } parser->code_size += size; if (pending != NULL && pending->u.variable->state == NJS_VARIABLE_PENDING) { pending->u.variable->state = NJS_VARIABLE_SET; if (!parser->branch) { pending->state = NJS_VARIABLE_FIRST_ASSIGNMENT; } } } }
njs_token_t njs_parser_var_expression(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) { size_t size; njs_parser_node_t *node, *pending; njs_vmcode_operation_t operation; token = njs_parser_conditional_expression(vm, parser, token); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } for ( ;; ) { size = sizeof(njs_vmcode_3addr_t); switch (token) { case NJS_TOKEN_ASSIGNMENT: nxt_thread_log_debug("JS: ="); operation = njs_vmcode_move; size = sizeof(njs_vmcode_move_t); break; case NJS_TOKEN_LINE_END: token = njs_lexer_token(parser->lexer); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } if (njs_parser_expression_operator(token)) { continue; } /* Fall through. */ default: return token; } node = parser->node; if (node->lvalue == NJS_LVALUE_NONE) { nxt_thread_log_error(NXT_LOG_ALERT, "lvalue required"); return NJS_TOKEN_ILLEGAL; } pending = NULL; if (node->token == NJS_TOKEN_NAME) { node->state = NJS_VARIABLE_ASSIGNMENT; if (node->u.variable->state == NJS_VARIABLE_PENDING) { pending = node; } } node = njs_parser_node_alloc(vm); if (nxt_slow_path(node == NULL)) { return NJS_TOKEN_ERROR; } node->token = token; node->u.operation = operation; node->left = parser->node; parser->code_size += size; token = njs_parser_token(parser); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } token = njs_parser_var_expression(vm, parser, token); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } node->right = parser->node; parser->node = node; if (pending != NULL && pending->u.variable->state == NJS_VARIABLE_PENDING) { pending->u.variable->state = NJS_VARIABLE_SET; parser->code_size -= sizeof(njs_vmcode_1addr_t); if (!parser->branch) { pending->state = NJS_VARIABLE_FIRST_ASSIGNMENT; } } } }