njs_generate_try_left(njs_vm_t *vm, njs_generator_t *generator,
    njs_parser_node_t *node)
{
    njs_int_t                    ret;
    njs_index_t                  exit_index, catch_index;
    njs_jump_off_t               try_end_offset;
    njs_variable_t               *var;
    njs_vmcode_catch_t           *catch;
    njs_vmcode_try_end_t         *try_end;
    njs_generator_block_t        *try_block;
    njs_generator_try_ctx_t      *ctx;
    njs_vmcode_try_trampoline_t  *try_break, *try_continue;

    ctx = generator->context;

    try_block = ctx->try_block;
    exit_index = try_block->index;

    njs_generate_code(generator, njs_vmcode_try_end_t, try_end,
                      NJS_VMCODE_TRY_END, 0, NULL);
    try_end_offset = njs_code_offset(generator, try_end);

    if (try_block->exit != NULL) {
        ctx->try_exit_label = try_block->exit->label;

        njs_debug_generator(vm, "TRY   CTX    %p EXIT LABEL %V", ctx,
                            &ctx->try_exit_label);

        njs_generate_patch_block(vm, generator, try_block,
                                 NJS_GENERATOR_EXIT);

        njs_generate_code(generator, njs_vmcode_try_trampoline_t, try_break,
                          NJS_VMCODE_TRY_BREAK, 1, NULL);
        try_break->exit_value = exit_index;

        try_break->offset = -sizeof(njs_vmcode_try_end_t);

    } else {
        try_break = NULL;
    }

    if (try_block->continuation != NULL) {
        ctx->try_cont_label = try_block->continuation->label;

        njs_generate_patch_block(vm, generator, try_block,
                                 NJS_GENERATOR_CONTINUATION);

        njs_generate_code(generator, njs_vmcode_try_trampoline_t, try_continue,
                          NJS_VMCODE_TRY_CONTINUE, 1, NULL);
        try_continue->exit_value = exit_index;

        try_continue->offset = -sizeof(njs_vmcode_try_end_t);

        if (try_break != NULL) {
            try_continue->offset -= sizeof(njs_vmcode_try_trampoline_t);
        }
    }

    njs_debug_generator(vm, "EXIT  %s %p",
                        njs_block_type(generator->block->type),
                        generator->block);

    generator->block = try_block->next;

    njs_code_set_jump_offset(generator, njs_vmcode_try_start_t,
                             ctx->try_offset);
    ctx->try_offset = try_end_offset;

    node = node->right;

    if (node->token_type == NJS_TOKEN_CATCH) {
        /* A "try/catch" case. */

        var = njs_variable_reference(vm, node->left);
        if (njs_slow_path(var == NULL)) {
            return NJS_ERROR;
        }

        catch_index = node->left->index;

        njs_generate_code_catch(generator, catch, catch_index, node);

        njs_generator_next(generator, njs_generate, node->right);

        return njs_generator_after(vm, generator,
                                   njs_queue_first(&generator->stack), node,
                                   njs_generate_try_catch, ctx, 0);
    }

    if (node->left != NULL) {
        /* A try/catch/finally case. */

        var = njs_variable_reference(vm, node->left->left);
        if (njs_slow_path(var == NULL)) {
            return NJS_ERROR;
        }

        catch_index = node->left->left->index;

        njs_generate_code_catch(generator, catch, catch_index, node);
        ctx->catch_offset = njs_code_offset(generator, catch);

        ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_TRY,
                                       &no_label);
        if (njs_slow_path(ret != NJS_OK)) {
            return ret;
        }

        ctx->catch_block = generator->block;
        ctx->catch_block->index = exit_index;

        njs_generator_next(generator, njs_generate, node->left->right);

        return njs_generator_after(vm, generator,
                                   njs_queue_first(&generator->stack), node,
                                   njs_generate_try_finally, ctx, 0);
    }

    /* A try/finally case. */

    njs_generate_code_catch(generator, catch, ctx->exception_index, NULL);

    ctx->catch_block = NULL;

    njs_code_set_jump_offset(generator, njs_vmcode_try_end_t,
                             ctx->try_offset);

    njs_generator_next(generator, njs_generate, node->right);

    return njs_generator_after(vm, generator,
                               njs_queue_first(&generator->stack), node,
                               njs_generate_try_end, ctx, 0);
}