njs_token_t njs_parser_token(njs_parser_t *parser) { njs_token_t token; do { token = njs_lexer_token(parser->lexer); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } } while (nxt_slow_path(token == NJS_TOKEN_LINE_END)); return token; }
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; } } } }
static njs_token_t njs_parser_binary_expression(njs_vm_t *vm, njs_parser_t *parser, const njs_parser_expression_t *expr, njs_token_t token) { nxt_int_t n; njs_parser_node_t *node; const njs_parser_operation_t *op; token = expr->next(vm, parser, expr->expression, token); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } for ( ;; ) { n = expr->count; op = expr->op; do { if (op->token == token) { goto found; } op++; n--; } while (n != 0); if (token == 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; } } return token; found: node = njs_parser_node_alloc(vm); if (nxt_slow_path(node == NULL)) { return NJS_TOKEN_ERROR; } node->token = token; node->u.operation = op->operation; node->left = parser->node; node->left->dest = node; parser->code_size += op->size; token = njs_parser_token(parser); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } token = expr->next(vm, parser, expr->expression, token); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } node->right = parser->node; node->right->dest = node; parser->node = node; } }
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; } } } }