示例#1
0
int parser_t::eval_block_node(node_offset_t node_idx, const io_chain_t &io,
                              enum block_type_t block_type) {
    // Paranoia. It's a little frightening that we're given only a node_idx and we interpret this in
    // the topmost execution context's tree. What happens if two trees were to be interleaved?
    // Fortunately that cannot happen (yet); in the future we probably want some sort of reference
    // counted trees.
    parse_execution_context_t *ctx = execution_contexts.back();
    assert(ctx != NULL);

    CHECK_BLOCK(1);

    // Handle cancellation requests. If our block stack is currently empty, then we already did
    // successfully cancel (or there was nothing to cancel); clear the flag. If our block stack is
    // not empty, we are still in the process of cancelling; refuse to evaluate anything.
    if (this->cancellation_requested) {
        if (!block_stack.empty()) {
            return 1;
        }
        this->cancellation_requested = false;
    }

    // Only certain blocks are allowed.
    if ((block_type != TOP) && (block_type != SUBST)) {
        debug(1, INVALID_SCOPE_ERR_MSG, parser_t::get_block_desc(block_type));
        bugreport();
        return 1;
    }

    job_reap(0);  // not sure why we reap jobs here

    /* Start it up */
    const block_t *const start_current_block = current_block();
    block_t *scope_block = new scope_block_t(block_type);
    this->push_block(scope_block);
    int result = ctx->eval_node_at_offset(node_idx, scope_block, io);

    // Clean up the block stack.
    this->pop_block();
    while (start_current_block != current_block()) {
        if (current_block() == NULL) {
            debug(0, _(L"End of block mismatch. Program terminating."));
            bugreport();
            FATAL_EXIT();
            break;
        }
        this->pop_block();
    }

    job_reap(0);  // reap again

    return result;
}
示例#2
0
void parser_t::pop_block()
{
    if (block_stack.empty())
    {
        debug(1,
              L"function %s called on empty block stack.",
              __func__);
        bugreport();
        return;
    }

    block_t *old = block_stack.back();
    block_stack.pop_back();

    if (old->wants_pop_env)
        env_pop();

    delete old;

    // Figure out if `status -b` should consider us to be in a block now
    int new_is_block=0;
    for (std::vector<block_t*>::const_iterator it = block_stack.begin(), end = block_stack.end(); it != end; ++it)
    {
        const enum block_type_t type = (*it)->type();
        if (type != TOP && type != SUBST)
        {
            new_is_block = 1;
            break;
        }
    }
    is_block = new_is_block;
}
示例#3
0
int parser_t::eval(const wcstring &cmd, const io_chain_t &io, enum block_type_t block_type)
{
    CHECK_BLOCK(1);

    if (block_type != TOP && block_type != SUBST)
    {
        debug(1, INVALID_SCOPE_ERR_MSG, parser_t::get_block_desc(block_type));
        bugreport();
        return 1;
    }

    /* Parse the source into a tree, if we can */
    parse_node_tree_t tree;
    parse_error_list_t error_list;
    if (! parse_tree_from_string(cmd, parse_flag_none, &tree, this->show_errors ? &error_list : NULL))
    {
        if (this->show_errors)
        {
            /* Get a backtrace */
            wcstring backtrace_and_desc;
            this->get_backtrace(cmd, error_list, &backtrace_and_desc);

            /* Print it */
            fprintf(stderr, "%ls", backtrace_and_desc.c_str());
        }

        return 1;
    }

    //print_stderr(block_stack_description());


    /* Determine the initial eval level. If this is the first context, it's -1; otherwise it's the eval level of the top context. This is sort of wonky because we're stitching together a global notion of eval level from these separate objects. A better approach would be some profile object that all contexts share, and that tracks the eval levels on its own. */
    int exec_eval_level = (execution_contexts.empty() ? -1 : execution_contexts.back()->current_eval_level());

    /* Append to the execution context stack */
    parse_execution_context_t *ctx = new parse_execution_context_t(tree, cmd, this, exec_eval_level);
    execution_contexts.push_back(ctx);

    /* Execute the first node */
    if (! tree.empty())
    {
        this->eval_block_node(0, io, block_type);
    }

    /* Clean up the execution context stack */
    assert(! execution_contexts.empty() && execution_contexts.back() == ctx);
    execution_contexts.pop_back();
    delete ctx;

    return 0;
}
示例#4
0
void signal_unblock() {
    ASSERT_IS_MAIN_THREAD();
    sigset_t chldset;

    block_count--;

    if (block_count < 0) {
        debug(0, _(L"Signal block mismatch"));
        bugreport();
        FATAL_EXIT();
    }

    if (!block_count) {
        sigfillset(&chldset);
        VOMIT_ON_FAILURE(pthread_sigmask(SIG_UNBLOCK, &chldset, 0));
    }
    //	debug( 0, L"signal block level decreased to %d", block_count );
}
示例#5
0
void parser_t::pop_block()
{
    if (block_stack.empty())
    {
        debug(1,
              L"function %s called on empty block stack.",
              __func__);
        bugreport();
        return;
    }

    block_t *old = block_stack.back();
    block_stack.pop_back();

    if (old->wants_pop_env)
        env_pop();

    delete old;
}
示例#6
0
int parser_t::eval_node(parsed_source_ref_t ps, tnode_t<T> node, const io_chain_t &io,
                        enum block_type_t block_type) {
    static_assert(
        std::is_same<T, grammar::statement>::value || std::is_same<T, grammar::job_list>::value,
        "Unexpected node type");
    CHECK_BLOCK(1);

    // Handle cancellation requests. If our block stack is currently empty, then we already did
    // successfully cancel (or there was nothing to cancel); clear the flag. If our block stack is
    // not empty, we are still in the process of cancelling; refuse to evaluate anything.
    if (this->cancellation_requested) {
        if (!block_stack.empty()) {
            return 1;
        }
        this->cancellation_requested = false;
    }

    // Only certain blocks are allowed.
    if ((block_type != TOP) && (block_type != SUBST)) {
        debug(1, INVALID_SCOPE_ERR_MSG, parser_t::get_block_desc(block_type));
        bugreport();
        return 1;
    }

    job_reap(0);  // not sure why we reap jobs here

    // Start it up
    scope_block_t *scope_block = this->push_block<scope_block_t>(block_type);

    // Create and set a new execution context.
    using exc_ctx_ref_t = std::unique_ptr<parse_execution_context_t>;
    scoped_push<exc_ctx_ref_t> exc(&execution_context,
                                   make_unique<parse_execution_context_t>(ps, this));
    int result = execution_context->eval_node(node, scope_block, io);
    exc.restore();
    this->pop_block(scope_block);

    job_reap(0);  // reap again
    return result;
}
示例#7
0
void parser_t::pop_block(const block_t *expected) {
    assert(expected == this->current_block());
    if (block_stack.empty()) {
        debug(1, L"function %s called on empty block stack.", __func__);
        bugreport();
        return;
    }

    // acquire ownership out of the block stack
    // this will trigger deletion when it goes out of scope
    std::unique_ptr<block_t> old = std::move(block_stack.back());
    block_stack.pop_back();

    if (old->wants_pop_env) env_pop();

    // Figure out if `status is-block` should consider us to be in a block now.
    bool new_is_block = false;
    for (const auto &b : block_stack) {
        const enum block_type_t type = b->type();
        if (type != TOP && type != SUBST) {
            new_is_block = true;
            break;
        }
    }
    is_block = new_is_block;

    // Are we still in a breakpoint?
    bool new_is_breakpoint = false;
    for (const auto &b : block_stack) {
        const enum block_type_t type = b->type();
        if (type == BREAKPOINT) {
            new_is_breakpoint = true;
            break;
        }
    }
    is_breakpoint = new_is_breakpoint;
}