diff --git a/src/builtin.cpp b/src/builtin.cpp index 92a1e5b15..a017ed264 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -315,7 +315,7 @@ static int builtin_breakpoint(parser_t &parser, io_streams_t &streams, wchar_t * return STATUS_ILLEGAL_CMD; } - const breakpoint_block_t *bpb = parser.push_block(); + const block_t *bpb = parser.push_block(block_t::breakpoint_block()); reader_read(STDIN_FILENO, streams.io_chain ? *streams.io_chain : io_chain_t()); parser.pop_block(bpb); return parser.get_last_status(); diff --git a/src/builtin_source.cpp b/src/builtin_source.cpp index 6abb467f0..9198992e7 100644 --- a/src/builtin_source.cpp +++ b/src/builtin_source.cpp @@ -73,7 +73,7 @@ int builtin_source(parser_t &parser, io_streams_t &streams, wchar_t **argv) { fn_intern = intern(argv[optind]); } - const source_block_t *sb = parser.push_block(fn_intern); + const block_t *sb = parser.push_block(block_t::source_block(fn_intern)); reader_push_current_filename(fn_intern); // This is slightly subtle. If this is a bare `source` with no args then `argv + optind` already diff --git a/src/event.cpp b/src/event.cpp index e42a85921..5d5d1e9fb 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -284,7 +284,7 @@ static void event_fire_internal(const event_t &event) { parser_t &parser = parser_t::principal_parser(); auto prev_statuses = parser.get_last_statuses(); - event_block_t *b = parser.push_block(event); + block_t *b = parser.push_block(block_t::event_block(event)); parser.eval(buffer, io_chain_t(), TOP); parser.pop_block(b); proc_pop_interactive(); diff --git a/src/exec.cpp b/src/exec.cpp index f5937e546..894a83250 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -822,8 +822,8 @@ static bool exec_block_or_func_process(parser_t &parser, std::shared_ptr wcstring_list_t argv = p->get_argv_array().to_list(); // Remove the function name from argv. if (!argv.empty()) argv.erase(argv.begin()); - function_block_t *fb = - parser.push_block(func_name, argv, props->shadow_scope); + block_t *fb = + parser.push_block(block_t::function_block(func_name, argv, props->shadow_scope)); function_prepare_environment(parser.vars(), func_name, std::move(argv), inherit_vars); parser.forbid_function(func_name); diff --git a/src/parse_execution.cpp b/src/parse_execution.cpp index 20d240772..c46cf2471 100644 --- a/src/parse_execution.cpp +++ b/src/parse_execution.cpp @@ -288,7 +288,7 @@ parse_execution_result_t parse_execution_context_t::run_if_statement( // Execute any job list we got. if (job_list_to_execute) { - if_block_t *ib = parser->push_block(); + block_t *ib = parser->push_block(block_t::if_block()); run_job_list(job_list_to_execute, ib); if (should_cancel_execution(ib)) { result = parse_execution_cancelled; @@ -311,7 +311,7 @@ parse_execution_result_t parse_execution_context_t::run_if_statement( parse_execution_result_t parse_execution_context_t::run_begin_statement( tnode_t contents) { // Basic begin/end block. Push a scope block, run jobs, pop it - scope_block_t *sb = parser->push_block(BEGIN); + block_t *sb = parser->push_block(block_t::scope_block(BEGIN)); parse_execution_result_t ret = run_job_list(contents, sb); parser->pop_block(sb); @@ -408,7 +408,7 @@ parse_execution_result_t parse_execution_context_t::run_for_statement( return parse_execution_errored; } - for_block_t *fb = parser->push_block(); + block_t *fb = parser->push_block(block_t::for_block()); // Now drive the for loop. for (const wcstring &val : arguments) { @@ -486,7 +486,7 @@ parse_execution_result_t parse_execution_context_t::run_switch_statement( const wcstring &switch_value_expanded = switch_values_expanded.at(0).completion; - switch_block_t *sb = parser->push_block(); + block_t *sb = parser->push_block(block_t::switch_block()); // Expand case statements. tnode_t case_item_list = statement.child<3>(); @@ -585,7 +585,7 @@ parse_execution_result_t parse_execution_context_t::run_while_statement( // Push a while block and then check its cancellation reason. auto &ld = parser->libdata(); ld.loop_status = loop_status_t::normals; - while_block_t *wb = parser->push_block(); + block_t *wb = parser->push_block(block_t::while_block()); this->run_job_list(contents, wb); auto cancel_reason = this->cancellation_reason(wb); parser->pop_block(wb); diff --git a/src/parser.cpp b/src/parser.cpp index 872b34ce1..99c3188df 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -119,7 +119,8 @@ void parser_t::skip_all_blocks() { } // Given a new-allocated block, push it onto our block stack, acquiring ownership -void parser_t::push_block_int(block_t *new_current) { +block_t *parser_t::push_block(block_t &&block) { + std::unique_ptr new_current = make_unique(std::move(block)); const enum block_type_t type = new_current->type(); new_current->src_lineno = parser_t::get_lineno(); @@ -138,9 +139,6 @@ void parser_t::push_block_int(block_t *new_current) { new_current->skip = false; } - // Push it onto our stack. This acquires ownership because of unique_ptr. - this->block_stack.emplace_back(new_current); - // Types TOP and SUBST are not considered blocks for the purposes of `status is-block`. if (type != TOP && type != SUBST) { libdata().is_block = true; @@ -154,6 +152,10 @@ void parser_t::push_block_int(block_t *new_current) { vars().push(type == FUNCTION_CALL); new_current->wants_pop_env = true; } + + // Push it onto our stack and return it. + this->block_stack.push_back(std::move(new_current)); + return this->block_stack.back().get(); } void parser_t::pop_block(const block_t *expected) { @@ -666,7 +668,7 @@ int parser_t::eval_node(parsed_source_ref_t ps, tnode_t node, const io_chain_ job_reap(*this, false); // not sure why we reap jobs here // Start it up - scope_block_t *scope_block = this->push_block(block_type); + block_t *scope_block = this->push_block(block_t::scope_block(block_type)); // Create and set a new execution context. using exc_ctx_ref_t = std::unique_ptr; @@ -835,6 +837,36 @@ wcstring block_t::description() const { // Various block constructors. +block_t block_t::if_block() { return block_t(IF); } + +block_t block_t::event_block(event_t evt) { + block_t b{EVENT}; + b.event = std::move(evt); + return b; +} + +block_t block_t::function_block(wcstring name, wcstring_list_t args, bool shadows) { + block_t b{shadows ? FUNCTION_CALL : FUNCTION_CALL_NO_SHADOW}; + b.function_name = std::move(name); + b.function_args = std::move(args); + return b; +} + +block_t block_t::source_block(const wchar_t *src) { + block_t b{SOURCE}; + b.sourced_file = src; + return b; +} + +block_t block_t::for_block() { return block_t{FOR}; } +block_t block_t::while_block() { return block_t{WHILE}; } +block_t block_t::switch_block() { return block_t{SWITCH}; } +block_t block_t::scope_block(block_type_t type) { + assert((type == BEGIN || type == TOP || type == SUBST) && "Invalid scope type"); + return block_t(type); +} +block_t block_t::breakpoint_block() { return block_t(BREAKPOINT); } + if_block_t::if_block_t() : block_t(IF) {} event_block_t::event_block_t(const event_t &evt) : block_t(EVENT) { this->event = evt; } diff --git a/src/parser.h b/src/parser.h index ca29302a9..1998abf2d 100644 --- a/src/parser.h +++ b/src/parser.h @@ -92,6 +92,17 @@ struct block_t { /// Description of the block, for debugging. wcstring description() const; + /// Entry points for creating blocks. + static block_t if_block(); + static block_t event_block(event_t evt); + static block_t function_block(wcstring name, wcstring_list_t args, bool shadows); + static block_t source_block(const wchar_t *src); + static block_t for_block(); + static block_t while_block(); + static block_t switch_block(); + static block_t scope_block(block_type_t type); + static block_t breakpoint_block(); + /// Destructor virtual ~block_t(); }; @@ -230,9 +241,6 @@ class parser_t : public std::enable_shared_from_this { /// Helper for stack_trace(). void stack_trace_internal(size_t block_idx, wcstring *out) const; - /// Helper for push_block() - void push_block_int(block_t *b); - /// Create a parser. parser_t(); @@ -314,15 +322,9 @@ class parser_t : public std::enable_shared_from_this { statuses_t get_last_statuses() const { return vars().get_last_statuses(); } void set_last_statuses(statuses_t s) { vars().set_last_statuses(std::move(s)); } - /// Pushes a new block created with the given arguments - /// Returns a pointer to the block. The pointer is valid - /// until the call to pop_block() - template - BLOCKTYPE *push_block(Args &&... args) { - BLOCKTYPE *ret = new BLOCKTYPE(std::forward(args)...); - this->push_block_int(ret); - return ret; - } + /// Pushes a new block. Returns a pointer to the block, stored in the parser. The pointer is + /// valid until the call to pop_block() + block_t *push_block(block_t &&b); /// Remove the outermost block, asserting it's the given one. void pop_block(const block_t *b);