njs_generate(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node)
{
    if (node == NULL) {
        return njs_generator_stack_pop(vm, generator, NULL);
    }

    switch (node->token_type) {

    case NJS_TOKEN_VAR:
    case NJS_TOKEN_LET:
    case NJS_TOKEN_CONST:
        return njs_generate_var_statement(vm, generator, node);

    case NJS_TOKEN_IF:
        return njs_generate_if_statement(vm, generator, node);

    case NJS_TOKEN_CONDITIONAL:
        return njs_generate_cond_expression(vm, generator, node);

    case NJS_TOKEN_SWITCH:
        return njs_generate_switch_statement(vm, generator, node);

    case NJS_TOKEN_WHILE:
        return njs_generate_while_statement(vm, generator, node);

    case NJS_TOKEN_DO:
        return njs_generate_do_while_statement(vm, generator, node);

    case NJS_TOKEN_FOR:
        return njs_generate_for_statement(vm, generator, node);

    case NJS_TOKEN_FOR_IN:
        return njs_generate_for_in_statement(vm, generator, node);

    case NJS_TOKEN_CONTINUE:
        return njs_generate_continue_statement(vm, generator, node);

    case NJS_TOKEN_BREAK:
        return njs_generate_break_statement(vm, generator, node);

    case NJS_TOKEN_DEBUGGER:
        return njs_generate_debugger_statement(vm, generator, node);

    case NJS_TOKEN_STATEMENT:
        return njs_generate_statement(vm, generator, node);

    case NJS_TOKEN_BLOCK:
        return njs_generate_block_statement(vm, generator, node);

    case NJS_TOKEN_END:
        return njs_generate_stop_statement(vm, generator, node);

    case NJS_TOKEN_COMMA:
        return njs_generate_comma_expression(vm, generator, node);

    case NJS_TOKEN_ASSIGNMENT:
        return njs_generate_assignment(vm, generator, node);

    case NJS_TOKEN_BITWISE_OR_ASSIGNMENT:
    case NJS_TOKEN_BITWISE_XOR_ASSIGNMENT:
    case NJS_TOKEN_BITWISE_AND_ASSIGNMENT:
    case NJS_TOKEN_LEFT_SHIFT_ASSIGNMENT:
    case NJS_TOKEN_RIGHT_SHIFT_ASSIGNMENT:
    case NJS_TOKEN_UNSIGNED_RIGHT_SHIFT_ASSIGNMENT:
    case NJS_TOKEN_ADDITION_ASSIGNMENT:
    case NJS_TOKEN_SUBSTRACTION_ASSIGNMENT:
    case NJS_TOKEN_MULTIPLICATION_ASSIGNMENT:
    case NJS_TOKEN_EXPONENTIATION_ASSIGNMENT:
    case NJS_TOKEN_DIVISION_ASSIGNMENT:
    case NJS_TOKEN_REMAINDER_ASSIGNMENT:
        return njs_generate_operation_assignment(vm, generator, node);

    case NJS_TOKEN_BITWISE_OR:
    case NJS_TOKEN_BITWISE_XOR:
    case NJS_TOKEN_BITWISE_AND:
    case NJS_TOKEN_EQUAL:
    case NJS_TOKEN_NOT_EQUAL:
    case NJS_TOKEN_STRICT_EQUAL:
    case NJS_TOKEN_STRICT_NOT_EQUAL:
    case NJS_TOKEN_INSTANCEOF:
    case NJS_TOKEN_LESS:
    case NJS_TOKEN_LESS_OR_EQUAL:
    case NJS_TOKEN_GREATER:
    case NJS_TOKEN_GREATER_OR_EQUAL:
    case NJS_TOKEN_LEFT_SHIFT:
    case NJS_TOKEN_RIGHT_SHIFT:
    case NJS_TOKEN_UNSIGNED_RIGHT_SHIFT:
    case NJS_TOKEN_ADDITION:
    case NJS_TOKEN_SUBSTRACTION:
    case NJS_TOKEN_MULTIPLICATION:
    case NJS_TOKEN_EXPONENTIATION:
    case NJS_TOKEN_DIVISION:
    case NJS_TOKEN_REMAINDER:
    case NJS_TOKEN_PROPERTY_DELETE:
    case NJS_TOKEN_PROPERTY:
        return njs_generate_3addr_operation(vm, generator, node, 0);

    case NJS_TOKEN_IN:
        /*
         * An "in" operation is parsed as standard binary expression
         * by njs_parser_binary_expression().  However, its operands
         * should be swapped to be uniform with other property operations
         * (get/set and delete) to use the property trap.
         */
        return njs_generate_3addr_operation(vm, generator, node, 1);

    case NJS_TOKEN_LOGICAL_AND:
    case NJS_TOKEN_LOGICAL_OR:
    case NJS_TOKEN_COALESCE:
        return njs_generate_test_jump_expression(vm, generator, node);

    case NJS_TOKEN_DELETE:
    case NJS_TOKEN_VOID:
    case NJS_TOKEN_UNARY_PLUS:
    case NJS_TOKEN_UNARY_NEGATION:
    case NJS_TOKEN_LOGICAL_NOT:
    case NJS_TOKEN_BITWISE_NOT:
        return njs_generate_2addr_operation(vm, generator, node);

    case NJS_TOKEN_TYPEOF:
        return njs_generate_typeof_operation(vm, generator, node);

    case NJS_TOKEN_INCREMENT:
    case NJS_TOKEN_DECREMENT:
        return njs_generate_inc_dec_operation(vm, generator, node, 0);

    case NJS_TOKEN_POST_INCREMENT:
    case NJS_TOKEN_POST_DECREMENT:
        return njs_generate_inc_dec_operation(vm, generator, node, 1);

    case NJS_TOKEN_NULL:
    case NJS_TOKEN_TRUE:
    case NJS_TOKEN_FALSE:
    case NJS_TOKEN_NUMBER:
    case NJS_TOKEN_STRING:
        node->index = njs_scope_global_index(vm, &node->u.value,
                                             generator->runtime);
        if (njs_slow_path(node->index == NJS_INDEX_ERROR)) {
            return NJS_ERROR;
        }

        return njs_generator_stack_pop(vm, generator, NULL);

    case NJS_TOKEN_OBJECT_VALUE:
        node->index = node->u.object->index;
        return njs_generator_stack_pop(vm, generator, NULL);

    case NJS_TOKEN_OBJECT:
        return njs_generate_object(vm, generator, node);

    case NJS_TOKEN_PROPERTY_GETTER:
    case NJS_TOKEN_PROPERTY_SETTER:
        return njs_generate_property_accessor(vm, generator, node);

    case NJS_TOKEN_ARRAY:
        return njs_generate_array(vm, generator, node);

    case NJS_TOKEN_FUNCTION_EXPRESSION:
    case NJS_TOKEN_ASYNC_FUNCTION_EXPRESSION:
        return njs_generate_function_expression(vm, generator, node);

    case NJS_TOKEN_FUNCTION:
    case NJS_TOKEN_ASYNC_FUNCTION:
        return njs_generate_function(vm, generator, node);

    case NJS_TOKEN_REGEXP:
        return njs_generate_regexp(vm, generator, node);

    case NJS_TOKEN_TEMPLATE_LITERAL:
        return njs_generate_template_literal(vm, generator, node);

    case NJS_TOKEN_EXTERNAL:
        return njs_generator_stack_pop(vm, generator, NULL);

    case NJS_TOKEN_NAME:
    case NJS_TOKEN_ARGUMENTS:
    case NJS_TOKEN_EVAL:
    case NJS_TOKEN_THIS:
        return njs_generate_name(vm, generator, node);

    case NJS_TOKEN_FUNCTION_DECLARATION:
    case NJS_TOKEN_ASYNC_FUNCTION_DECLARATION:
        return njs_generate_function_declaration(vm, generator, node);

    case NJS_TOKEN_FUNCTION_CALL:
        return njs_generate_function_call(vm, generator, node);

    case NJS_TOKEN_RETURN:
        return njs_generate_return_statement(vm, generator, node);

    case NJS_TOKEN_METHOD_CALL:
        return njs_generate_method_call(vm, generator, node);

    case NJS_TOKEN_TRY:
        return njs_generate_try_statement(vm, generator, node);

    case NJS_TOKEN_THROW:
        return njs_generate_throw_statement(vm, generator, node);

    case NJS_TOKEN_IMPORT:
        return njs_generate_import_statement(vm, generator, node);

    case NJS_TOKEN_EXPORT:
        return njs_generate_export_statement(vm, generator, node);

    case NJS_TOKEN_AWAIT:
        return njs_generate_await(vm, generator, node);

    default:
        njs_internal_error(vm, "Generator failed: unknown token");

        return NJS_ERROR;
    }
}
njs_generate(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node)
{
    if (node == NULL) {
        return njs_generator_stack_pop(vm, generator, NULL);
    }

    switch (node->token_type) {

    case NJS_TOKEN_VAR:
    case NJS_TOKEN_LET:
    case NJS_TOKEN_CONST:
        return njs_generate_var_statement(vm, generator, node);

    case NJS_TOKEN_IF:
        return njs_generate_if_statement(vm, generator, node);

    case NJS_TOKEN_CONDITIONAL:
        return njs_generate_cond_expression(vm, generator, node);

    case NJS_TOKEN_SWITCH:
        return njs_generate_switch_statement(vm, generator, node);

    case NJS_TOKEN_WHILE:
        return njs_generate_while_statement(vm, generator, node);

    case NJS_TOKEN_DO:
        return njs_generate_do_while_statement(vm, generator, node);

    case NJS_TOKEN_FOR:
        return njs_generate_for_statement(vm, generator, node);

    case NJS_TOKEN_FOR_IN:
        return njs_generate_for_in_statement(vm, generator, node);

    case NJS_TOKEN_CONTINUE:
        return njs_generate_continue_statement(vm, generator, node);

    case NJS_TOKEN_BREAK:
        return njs_generate_break_statement(vm, generator, node);

    case NJS_TOKEN_DEBUGGER:
        return njs_generate_debugger_statement(vm, generator, node);

    case NJS_TOKEN_STATEMENT:
        return njs_generate_statement(vm, generator, node);

    case NJS_TOKEN_BLOCK:
        return njs_generate_block_statement(vm, generator, node);

    case NJS_TOKEN_END:
        return njs_generate_stop_statement(vm, generator, node);

    case NJS_TOKEN_COMMA:
        return njs_generate_comma_expression(vm, generator, node);

    case NJS_TOKEN_ASSIGNMENT:
        return njs_generate_assignment(vm, generator, node);

    case NJS_TOKEN_BITWISE_OR_ASSIGNMENT:
    case NJS_TOKEN_BITWISE_XOR_ASSIGNMENT:
    case NJS_TOKEN_BITWISE_AND_ASSIGNMENT:
    case NJS_TOKEN_LEFT_SHIFT_ASSIGNMENT:
    case NJS_TOKEN_RIGHT_SHIFT_ASSIGNMENT:
    case NJS_TOKEN_UNSIGNED_RIGHT_SHIFT_ASSIGNMENT:
    case NJS_TOKEN_ADDITION_ASSIGNMENT:
    case NJS_TOKEN_SUBSTRACTION_ASSIGNMENT:
    case NJS_TOKEN_MULTIPLICATION_ASSIGNMENT:
    case NJS_TOKEN_EXPONENTIATION_ASSIGNMENT:
    case NJS_TOKEN_DIVISION_ASSIGNMENT:
    case NJS_TOKEN_REMAINDER_ASSIGNMENT:
        return njs_generate_operation_assignment(vm, generator, node);

    case NJS_TOKEN_BITWISE_OR:
    case NJS_TOKEN_BITWISE_XOR:
    case NJS_TOKEN_BITWISE_AND:
    case NJS_TOKEN_EQUAL:
    case NJS_TOKEN_NOT_EQUAL:
    case NJS_TOKEN_STRICT_EQUAL:
    case NJS_TOKEN_STRICT_NOT_EQUAL:
    case NJS_TOKEN_INSTANCEOF:
    case NJS_TOKEN_LESS:
    case NJS_TOKEN_LESS_OR_EQUAL:
    case NJS_TOKEN_GREATER:
    case NJS_TOKEN_GREATER_OR_EQUAL:
    case NJS_TOKEN_LEFT_SHIFT:
    case NJS_TOKEN_RIGHT_SHIFT:
    case NJS_TOKEN_UNSIGNED_RIGHT_SHIFT:
    case NJS_TOKEN_ADDITION:
    case NJS_TOKEN_SUBSTRACTION:
    case NJS_TOKEN_MULTIPLICATION:
    case NJS_TOKEN_EXPONENTIATION:
    case NJS_TOKEN_DIVISION:
    case NJS_TOKEN_REMAINDER:
    case NJS_TOKEN_PROPERTY_DELETE:
    case NJS_TOKEN_PROPERTY:
        return njs_generate_3addr_operation(vm, generator, node, 0);

    case NJS_TOKEN_IN:
         
        return njs_generate_3addr_operation(vm, generator, node, 1);

    case NJS_TOKEN_LOGICAL_AND:
    case NJS_TOKEN_LOGICAL_OR:
    case NJS_TOKEN_COALESCE:
        return njs_generate_test_jump_expression(vm, generator, node);

    case NJS_TOKEN_DELETE:
    case NJS_TOKEN_VOID:
    case NJS_TOKEN_UNARY_PLUS:
    case NJS_TOKEN_UNARY_NEGATION:
    case NJS_TOKEN_LOGICAL_NOT:
    case NJS_TOKEN_BITWISE_NOT:
        return njs_generate_2addr_operation(vm, generator, node);

    case NJS_TOKEN_TYPEOF:
        return njs_generate_typeof_operation(vm, generator, node);

    case NJS_TOKEN_INCREMENT:
    case NJS_TOKEN_DECREMENT:
        return njs_generate_inc_dec_operation(vm, generator, node, 0);

    case NJS_TOKEN_POST_INCREMENT:
    case NJS_TOKEN_POST_DECREMENT:
        return njs_generate_inc_dec_operation(vm, generator, node, 1);

    case NJS_TOKEN_NULL:
    case NJS_TOKEN_TRUE:
    case NJS_TOKEN_FALSE:
    case NJS_TOKEN_NUMBER:
    case NJS_TOKEN_STRING:
        node->index = njs_scope_global_index(vm, &node->u.value,
                                             generator->runtime);
        if (njs_slow_path(node->index == NJS_INDEX_ERROR)) {
            return NJS_ERROR;
        }

        return njs_generator_stack_pop(vm, generator, NULL);

    case NJS_TOKEN_OBJECT_VALUE:
        node->index = node->u.object->index;
        return njs_generator_stack_pop(vm, generator, NULL);

    case NJS_TOKEN_OBJECT:
        return njs_generate_object(vm, generator, node);

    case NJS_TOKEN_PROPERTY_GETTER:
    case NJS_TOKEN_PROPERTY_SETTER:
        return njs_generate_property_accessor(vm, generator, node);

    case NJS_TOKEN_ARRAY:
        return njs_generate_array(vm, generator, node);

    case NJS_TOKEN_FUNCTION_EXPRESSION:
    case NJS_TOKEN_ASYNC_FUNCTION_EXPRESSION:
        return njs_generate_function_expression(vm, generator, node);

    case NJS_TOKEN_FUNCTION:
    case NJS_TOKEN_ASYNC_FUNCTION:
        return njs_generate_function(vm, generator, node);

    case NJS_TOKEN_REGEXP:
        return njs_generate_regexp(vm, generator, node);

    case NJS_TOKEN_TEMPLATE_LITERAL:
        return njs_generate_template_literal(vm, generator, node);

    case NJS_TOKEN_EXTERNAL:
        return njs_generator_stack_pop(vm, generator, NULL);

    case NJS_TOKEN_NAME:
    case NJS_TOKEN_ARGUMENTS:
    case NJS_TOKEN_EVAL:
    case NJS_TOKEN_THIS:
        return njs_generate_name(vm, generator, node);

    case NJS_TOKEN_FUNCTION_DECLARATION:
    case NJS_TOKEN_ASYNC_FUNCTION_DECLARATION:
        return njs_generate_function_declaration(vm, generator, node);

    case NJS_TOKEN_FUNCTION_CALL:
        return njs_generate_function_call(vm, generator, node);

    case NJS_TOKEN_RETURN:
        return njs_generate_return_statement(vm, generator, node);

    case NJS_TOKEN_METHOD_CALL:
        return njs_generate_method_call(vm, generator, node);

    case NJS_TOKEN_TRY:
        return njs_generate_try_statement(vm, generator, node);

    case NJS_TOKEN_THROW:
        return njs_generate_throw_statement(vm, generator, node);

    case NJS_TOKEN_IMPORT:
        return njs_generate_import_statement(vm, generator, node);

    case NJS_TOKEN_EXPORT:
        return njs_generate_export_statement(vm, generator, node);

    case NJS_TOKEN_AWAIT:
        return njs_generate_await(vm, generator, node);

    default:
        njs_internal_error(vm, "Generator failed: unknown token");

        return NJS_ERROR;
    }
}