mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-27 05:13:10 +00:00
New ideas about how to use new parser for execution. Beginnings of
implementation.
This commit is contained in:
parent
5b1a532652
commit
924b8cbe24
6 changed files with 143 additions and 137 deletions
|
@ -13,7 +13,7 @@
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
|
|
||||||
|
|
||||||
parse_execution_context_t::parse_execution_context_t(const parse_node_tree_t &t, const wcstring s, parser_t *p) : tree(t), src(s), parser(p)
|
parse_execution_context_t::parse_execution_context_t(const parse_node_tree_t &t, const wcstring s, parser_t *p) : tree(t), src(s), parser(p), eval_level(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,54 +31,48 @@ const parse_node_t *parse_execution_context_t::get_child(const parse_node_t &par
|
||||||
|
|
||||||
node_offset_t parse_execution_context_t::get_offset(const parse_node_t &node) const
|
node_offset_t parse_execution_context_t::get_offset(const parse_node_t &node) const
|
||||||
{
|
{
|
||||||
/* Pointer arithmetic, very hackish */
|
/* Get the offset of a node via pointer arithmetic, very hackish */
|
||||||
const parse_node_t *addr = &node;
|
const parse_node_t *addr = &node;
|
||||||
const parse_node_t *base = &this->tree.at(0);
|
const parse_node_t *base = &this->tree.at(0);
|
||||||
assert(addr >= base);
|
assert(addr >= base);
|
||||||
node_offset_t offset = addr - base;
|
node_offset_t offset = addr - base;
|
||||||
assert(offset < this->tree.size());
|
assert(offset < this->tree.size());
|
||||||
|
assert(&tree.at(offset) == &node);
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stack manipulation */
|
|
||||||
|
|
||||||
void parse_execution_context_t::stack_push(const parse_node_t *job_or_job_list, statement_completion_handler_t completion_handler, const parse_node_t *node)
|
bool parse_execution_context_t::should_cancel() const
|
||||||
{
|
{
|
||||||
const struct parse_execution_stack_element_t elem = {job_or_job_list, completion_handler, node};
|
return false;
|
||||||
job_stack.push_back(elem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
process_t *parse_execution_context_t::create_for_process(job_t *job, const parse_node_t &header, const parse_node_t &statement)
|
void parse_execution_context_t::run_while_process(const parse_node_t &header, const parse_node_t &statement)
|
||||||
{
|
|
||||||
assert(header.type == symbol_for_header);
|
|
||||||
const wcstring for_variable = get_source(*get_child(header, 1, parse_token_type_string));
|
|
||||||
const parse_node_t &arg_list = *get_child(header, 3, symbol_argument_list);
|
|
||||||
|
|
||||||
for_block_t *fb = new for_block_t(for_variable);
|
|
||||||
fb->sequence = this->determine_arguments(arg_list, NULL);
|
|
||||||
fb->node_offset = this->get_offset(statement);
|
|
||||||
parser->push_block(fb);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
process_t *parse_execution_context_t::create_while_process(job_t *job, const parse_node_t &header, const parse_node_t &statement)
|
|
||||||
{
|
{
|
||||||
assert(header.type == symbol_while_header);
|
assert(header.type == symbol_while_header);
|
||||||
|
assert(statement.type == symbol_block_statement);
|
||||||
|
|
||||||
while_block_t *wb = new while_block_t();
|
while_block_t *wb = new while_block_t();
|
||||||
wb->status = WHILE_TEST_FIRST;
|
wb->status = WHILE_TEST_FIRST;
|
||||||
wb->node_offset = this->get_offset(statement);
|
wb->node_offset = this->get_offset(statement);
|
||||||
parser->push_block(wb);
|
parser->push_block(wb);
|
||||||
return NULL;
|
|
||||||
|
// The condition of the while loop, as a job
|
||||||
|
const parse_node_t &while_condition = *get_child(header, 1, symbol_job);
|
||||||
|
|
||||||
|
// The contents of the while loop, as a job list
|
||||||
|
const parse_node_t &block_contents = *get_child(statement, 2, symbol_job_list);
|
||||||
|
|
||||||
|
// A while loop is a while loop!
|
||||||
|
while (! this->should_cancel() && this->run_1_job(while_condition) == EXIT_SUCCESS)
|
||||||
|
{
|
||||||
|
this->run_job_list(block_contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
process_t *parse_execution_context_t::create_begin_process(job_t *job, const parse_node_t &header, const parse_node_t &statement)
|
parser->pop_block(wb);
|
||||||
{
|
|
||||||
assert(header.type == symbol_begin_header);
|
|
||||||
scope_block_t *bb = new scope_block_t(BEGIN);
|
|
||||||
parser->push_block(bb);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool parse_execution_context_t::append_error(const parse_node_t &node, const wchar_t *fmt, ...)
|
bool parse_execution_context_t::append_error(const parse_node_t &node, const wchar_t *fmt, ...)
|
||||||
{
|
{
|
||||||
parse_error_t error;
|
parse_error_t error;
|
||||||
|
@ -382,6 +376,16 @@ process_t *parse_execution_context_t::create_boolean_process(job_t *job, const p
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
process_t *parse_execution_context_t::create_block_process(job_t *job, const parse_node_t &statement_node)
|
||||||
|
{
|
||||||
|
/* We handle block statements by creating INTERNAL_BLOCKs, that will bounce back to us when it's time to execute them */
|
||||||
|
assert(statement_node.type == symbol_block_statement || statement_node.type == symbol_if_statement || statement_node.type == symbol_switch_statement);
|
||||||
|
process_t *result = new process_t();
|
||||||
|
result->type = INTERNAL_BLOCK;
|
||||||
|
result->internal_block_node = this->get_offset(statement_node);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Returns a process_t allocated with new. It's the caller's responsibility to delete it (!) */
|
/* Returns a process_t allocated with new. It's the caller's responsibility to delete it (!) */
|
||||||
process_t *parse_execution_context_t::create_job_process(job_t *job, const parse_node_t &statement_node)
|
process_t *parse_execution_context_t::create_job_process(job_t *job, const parse_node_t &statement_node)
|
||||||
|
@ -403,34 +407,10 @@ process_t *parse_execution_context_t::create_job_process(job_t *job, const parse
|
||||||
}
|
}
|
||||||
|
|
||||||
case symbol_block_statement:
|
case symbol_block_statement:
|
||||||
|
case symbol_if_statement:
|
||||||
|
case symbol_switch_statement:
|
||||||
{
|
{
|
||||||
const parse_node_t &header = *get_child(specific_statement, 0, symbol_block_header);
|
result = this->create_block_process(job, specific_statement);
|
||||||
const parse_node_t &specific_header = *get_child(header, 0);
|
|
||||||
switch (specific_header.type)
|
|
||||||
{
|
|
||||||
case symbol_for_header:
|
|
||||||
result = this->create_for_process(job, specific_header, specific_statement);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case symbol_while_header:
|
|
||||||
result = this->create_while_process(job, specific_header, specific_statement);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case symbol_function_header:
|
|
||||||
// No process is associated with creating a function
|
|
||||||
// TODO: create the darn function!
|
|
||||||
result = NULL;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case symbol_begin_header:
|
|
||||||
result = this->create_begin_process(job, specific_header, specific_statement);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "Unexpected header type\n");
|
|
||||||
PARSER_DIE();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,13 +423,15 @@ process_t *parse_execution_context_t::create_job_process(job_t *job, const parse
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "'%ls' not handled by new parser yet\n", specific_statement.describe().c_str());
|
fprintf(stderr, "'%ls' not handled by new parser yet\n", specific_statement.describe().c_str());
|
||||||
|
PARSER_DIE();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void parse_execution_context_t::eval_job(job_t *j, const parse_node_t &job_node)
|
void parse_execution_context_t::populate_job_from_job_node(job_t *j, const parse_node_t &job_node)
|
||||||
{
|
{
|
||||||
assert(job_node.type == symbol_job);
|
assert(job_node.type == symbol_job);
|
||||||
|
|
||||||
|
@ -459,7 +441,7 @@ void parse_execution_context_t::eval_job(job_t *j, const parse_node_t &job_node)
|
||||||
/* Tell the job what its command is */
|
/* Tell the job what its command is */
|
||||||
j->set_command(get_source(job_node));
|
j->set_command(get_source(job_node));
|
||||||
|
|
||||||
/* We are going ot construct process_t structures for every statement in the job. Get the first statement. */
|
/* We are going to construct process_t structures for every statement in the job. Get the first statement. */
|
||||||
const parse_node_t *statement_node = get_child(job_node, 0, symbol_statement);
|
const parse_node_t *statement_node = get_child(job_node, 0, symbol_statement);
|
||||||
assert(statement_node != NULL);
|
assert(statement_node != NULL);
|
||||||
|
|
||||||
|
@ -468,7 +450,7 @@ void parse_execution_context_t::eval_job(job_t *j, const parse_node_t &job_node)
|
||||||
if (j->first_process == NULL)
|
if (j->first_process == NULL)
|
||||||
process_errored = true;
|
process_errored = true;
|
||||||
|
|
||||||
/* Construct process_ts for job continuations (pipelines), by walking the list until we hit the terminal (empty) job continuationf */
|
/* Construct process_ts for job continuations (pipelines), by walking the list until we hit the terminal (empty) job continuation */
|
||||||
const parse_node_t *job_cont = get_child(job_node, 1, symbol_job_continuation);
|
const parse_node_t *job_cont = get_child(job_node, 1, symbol_job_continuation);
|
||||||
process_t *last_process = j->first_process;
|
process_t *last_process = j->first_process;
|
||||||
while (! process_errored && job_cont != NULL && job_cont->child_count > 0)
|
while (! process_errored && job_cont != NULL && job_cont->child_count > 0)
|
||||||
|
@ -490,7 +472,7 @@ void parse_execution_context_t::eval_job(job_t *j, const parse_node_t &job_node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_execution_context_t::eval_1_job(const parse_node_t &job_node)
|
int parse_execution_context_t::run_1_job(const parse_node_t &job_node)
|
||||||
{
|
{
|
||||||
// Get terminal modes
|
// Get terminal modes
|
||||||
struct termios tmodes = {};
|
struct termios tmodes = {};
|
||||||
|
@ -500,12 +482,17 @@ void parse_execution_context_t::eval_1_job(const parse_node_t &job_node)
|
||||||
{
|
{
|
||||||
// need real error handling here
|
// need real error handling here
|
||||||
wperror(L"tcgetattr");
|
wperror(L"tcgetattr");
|
||||||
return;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Increment the eval_level for the duration of this command */
|
||||||
|
scoped_push<int> saved_eval_level(&eval_level, eval_level + 1);
|
||||||
|
|
||||||
|
/* TODO: blocks-without-redirections optimization */
|
||||||
|
|
||||||
/* Profiling support */
|
/* Profiling support */
|
||||||
long long t1 = 0, t2 = 0, t3 = 0;
|
long long start_time = 0, parse_time = 0, exec_time = 0;
|
||||||
const bool do_profile = profile;
|
const bool do_profile = profile;
|
||||||
profile_item_t *profile_item = NULL;
|
profile_item_t *profile_item = NULL;
|
||||||
if (do_profile)
|
if (do_profile)
|
||||||
|
@ -513,7 +500,7 @@ void parse_execution_context_t::eval_1_job(const parse_node_t &job_node)
|
||||||
profile_item = new profile_item_t();
|
profile_item = new profile_item_t();
|
||||||
profile_item->skipped = 1;
|
profile_item->skipped = 1;
|
||||||
profile_items.push_back(profile_item);
|
profile_items.push_back(profile_item);
|
||||||
t1 = get_time();
|
start_time = get_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
job_t *j = parser->job_create();
|
job_t *j = parser->job_create();
|
||||||
|
@ -528,27 +515,50 @@ void parse_execution_context_t::eval_1_job(const parse_node_t &job_node)
|
||||||
|
|
||||||
parser->current_block()->job = j;
|
parser->current_block()->job = j;
|
||||||
|
|
||||||
this->eval_job(j, job_node);
|
this->populate_job_from_job_node(j, job_node);
|
||||||
|
|
||||||
|
if (do_profile)
|
||||||
|
{
|
||||||
|
parse_time = get_time();
|
||||||
|
profile_item->cmd = j->command();
|
||||||
|
profile_item->skipped=parser->current_block()->skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_execution_context_t::eval_next_stack_elem()
|
/* Check to see if this contained any external commands */
|
||||||
|
bool job_contained_external_command = false;
|
||||||
|
for (const process_t *proc = j->first_process; proc != NULL; proc = proc->next)
|
||||||
{
|
{
|
||||||
// Pop the next thing to do
|
if (proc->type == EXTERNAL)
|
||||||
assert(! job_stack.empty());
|
|
||||||
const parse_execution_stack_element_t elem = job_stack.back();
|
|
||||||
job_stack.pop_back();
|
|
||||||
|
|
||||||
assert(elem.job_or_job_list->type == symbol_job || elem.job_or_job_list->type == symbol_job_list);
|
|
||||||
|
|
||||||
if (elem.job_or_job_list->type == symbol_job)
|
|
||||||
{
|
{
|
||||||
const parse_node_t *job = elem.job_or_job_list;
|
job_contained_external_command = true;
|
||||||
this->eval_1_job(*job);
|
break;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
/* Only external commands require a new fishd barrier */
|
||||||
|
if (!job_contained_external_command)
|
||||||
|
set_proc_had_barrier(false);
|
||||||
|
|
||||||
|
/* Need support for skipped_exec here */
|
||||||
|
|
||||||
|
if (do_profile)
|
||||||
{
|
{
|
||||||
const parse_node_t *job_list = elem.job_or_job_list;
|
exec_time = get_time();
|
||||||
|
profile_item->level=eval_level;
|
||||||
|
profile_item->parse = (int)(parse_time-start_time);
|
||||||
|
profile_item->exec=(int)(exec_time-parse_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
job_reap(0);
|
||||||
|
|
||||||
|
return proc_get_last_status();
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_execution_context_t::run_job_list(const parse_node_t &job_list_node)
|
||||||
|
{
|
||||||
|
assert(job_list_node.type == symbol_job_list);
|
||||||
|
|
||||||
|
const parse_node_t *job_list = &job_list_node;
|
||||||
while (job_list != NULL)
|
while (job_list != NULL)
|
||||||
{
|
{
|
||||||
assert(job_list->type == symbol_job_list);
|
assert(job_list->type == symbol_job_list);
|
||||||
|
@ -578,24 +588,14 @@ void parse_execution_context_t::eval_next_stack_elem()
|
||||||
|
|
||||||
if (job != NULL)
|
if (job != NULL)
|
||||||
{
|
{
|
||||||
this->eval_1_job(*job);
|
this->run_1_job(*job);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Invoke any completion handler */
|
|
||||||
if (elem.completion_handler)
|
|
||||||
{
|
|
||||||
assert(elem.node != NULL);
|
|
||||||
(this->*elem.completion_handler)(*elem.node);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_execution_context_t::eval_job_list(const parse_node_t &job_node)
|
|
||||||
{
|
|
||||||
this->stack_push(&job_node, NULL, NULL);
|
|
||||||
while (! job_stack.empty())
|
|
||||||
{
|
|
||||||
this->eval_next_stack_elem();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void parse_execution_context_t::eval_job_list(const parse_node_t &job_list_node)
|
||||||
|
{
|
||||||
|
this->run_job_list(job_list_node);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,26 +22,16 @@ class parse_execution_context_t
|
||||||
parser_t * const parser;
|
parser_t * const parser;
|
||||||
parse_error_list_t errors;
|
parse_error_list_t errors;
|
||||||
|
|
||||||
|
int eval_level;
|
||||||
std::vector<profile_item_t*> profile_items;
|
std::vector<profile_item_t*> profile_items;
|
||||||
|
|
||||||
/* We maintain a stack of job lists to be executed, and something to do after the execution is finished. This is a pointer to member function that takes a node, a status, and the statement that was executed */
|
|
||||||
typedef void (parse_execution_context_t::*statement_completion_handler_t)(const parse_node_t &node);
|
|
||||||
|
|
||||||
struct parse_execution_stack_element_t
|
|
||||||
{
|
|
||||||
// These point into our tree, which is immutable
|
|
||||||
const parse_node_t *job_or_job_list;
|
|
||||||
statement_completion_handler_t completion_handler;
|
|
||||||
const parse_node_t *node;
|
|
||||||
};
|
|
||||||
std::vector<parse_execution_stack_element_t> job_stack;
|
|
||||||
|
|
||||||
void stack_push(const parse_node_t *job_or_job_list, statement_completion_handler_t completion_handler, const parse_node_t *node);
|
|
||||||
|
|
||||||
/* No copying allowed */
|
/* No copying allowed */
|
||||||
parse_execution_context_t(const parse_execution_context_t&);
|
parse_execution_context_t(const parse_execution_context_t&);
|
||||||
parse_execution_context_t& operator=(const parse_execution_context_t&);
|
parse_execution_context_t& operator=(const parse_execution_context_t&);
|
||||||
|
|
||||||
|
/* Should I cancel */
|
||||||
|
bool should_cancel() const;
|
||||||
|
|
||||||
/* Report an error. Always returns true. */
|
/* Report an error. Always returns true. */
|
||||||
bool append_error(const parse_node_t &node, const wchar_t *fmt, ...);
|
bool append_error(const parse_node_t &node, const wchar_t *fmt, ...);
|
||||||
|
|
||||||
|
@ -52,16 +42,17 @@ class parse_execution_context_t
|
||||||
|
|
||||||
process_t *create_job_process(job_t *job, const parse_node_t &statement_node);
|
process_t *create_job_process(job_t *job, const parse_node_t &statement_node);
|
||||||
process_t *create_boolean_process(job_t *job, const parse_node_t &bool_statement);
|
process_t *create_boolean_process(job_t *job, const parse_node_t &bool_statement);
|
||||||
process_t *create_for_process(job_t *job, const parse_node_t &header, const parse_node_t &statement);
|
|
||||||
process_t *create_while_process(job_t *job, const parse_node_t &header, const parse_node_t &statement);
|
|
||||||
process_t *create_begin_process(job_t *job, const parse_node_t &header, const parse_node_t &statement);
|
|
||||||
process_t *create_plain_process(job_t *job, const parse_node_t &statement);
|
process_t *create_plain_process(job_t *job, const parse_node_t &statement);
|
||||||
|
process_t *create_block_process(job_t *job, const parse_node_t &statement_node);
|
||||||
|
|
||||||
|
void run_while_process(const parse_node_t &header, const parse_node_t &statement);
|
||||||
|
|
||||||
wcstring_list_t determine_arguments(const parse_node_t &parent, const parse_node_t **out_unmatched_wildcard_node);
|
wcstring_list_t determine_arguments(const parse_node_t &parent, const parse_node_t **out_unmatched_wildcard_node);
|
||||||
io_chain_t determine_io_chain(const parse_node_t &statement);
|
io_chain_t determine_io_chain(const parse_node_t &statement);
|
||||||
|
|
||||||
void eval_1_job(const parse_node_t &job_node);
|
int run_1_job(const parse_node_t &job_node);
|
||||||
void eval_job(job_t *j, const parse_node_t &job_node);
|
void run_job_list(const parse_node_t &job_list_node);
|
||||||
|
void populate_job_from_job_node(job_t *j, const parse_node_t &job_node);
|
||||||
|
|
||||||
void eval_next_stack_elem();
|
void eval_next_stack_elem();
|
||||||
|
|
||||||
|
|
|
@ -427,6 +427,12 @@ void parser_t::pop_block()
|
||||||
delete old;
|
delete old;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void parser_t::pop_block(const block_t *expected)
|
||||||
|
{
|
||||||
|
assert(expected == this->current_block());
|
||||||
|
this->pop_block();
|
||||||
|
}
|
||||||
|
|
||||||
const wchar_t *parser_t::get_block_desc(int block) const
|
const wchar_t *parser_t::get_block_desc(int block) const
|
||||||
{
|
{
|
||||||
for (size_t i=0; block_lookup[i].desc; i++)
|
for (size_t i=0; block_lookup[i].desc; i++)
|
||||||
|
@ -2908,7 +2914,9 @@ void parser_t::eval_job(tokenizer_t *tok)
|
||||||
{
|
{
|
||||||
int was_builtin = 0;
|
int was_builtin = 0;
|
||||||
if (j->first_process->type==INTERNAL_BUILTIN && !j->first_process->next)
|
if (j->first_process->type==INTERNAL_BUILTIN && !j->first_process->next)
|
||||||
|
{
|
||||||
was_builtin = 1;
|
was_builtin = 1;
|
||||||
|
}
|
||||||
scoped_push<int> tokenizer_pos_push(¤t_tokenizer_pos, job_begin_pos);
|
scoped_push<int> tokenizer_pos_push(¤t_tokenizer_pos, job_begin_pos);
|
||||||
exec_job(*this, j);
|
exec_job(*this, j);
|
||||||
|
|
||||||
|
|
3
parser.h
3
parser.h
|
@ -467,6 +467,9 @@ public:
|
||||||
/** Remove the outermost block namespace */
|
/** Remove the outermost block namespace */
|
||||||
void pop_block();
|
void pop_block();
|
||||||
|
|
||||||
|
/** Remove the outermost block, asserting it's the given one */
|
||||||
|
void pop_block(const block_t *b);
|
||||||
|
|
||||||
/** Return a description of the given blocktype */
|
/** Return a description of the given blocktype */
|
||||||
const wchar_t *get_block_desc(int block) const;
|
const wchar_t *get_block_desc(int block) const;
|
||||||
|
|
||||||
|
|
1
proc.cpp
1
proc.cpp
|
@ -516,6 +516,7 @@ process_t::process_t() :
|
||||||
argv_array(),
|
argv_array(),
|
||||||
argv0_narrow(),
|
argv0_narrow(),
|
||||||
type(),
|
type(),
|
||||||
|
internal_block_node(NODE_OFFSET_INVALID),
|
||||||
actual_cmd(),
|
actual_cmd(),
|
||||||
pid(0),
|
pid(0),
|
||||||
pipe_write_fd(0),
|
pipe_write_fd(0),
|
||||||
|
|
3
proc.h
3
proc.h
|
@ -20,6 +20,7 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "parse_tree.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The status code use when a command was not found
|
The status code use when a command was not found
|
||||||
|
@ -152,6 +153,8 @@ public:
|
||||||
*/
|
*/
|
||||||
enum process_type_t type;
|
enum process_type_t type;
|
||||||
|
|
||||||
|
/* For internal block processes only, the node offset of the block */
|
||||||
|
node_offset_t internal_block_node;
|
||||||
|
|
||||||
/** Sets argv */
|
/** Sets argv */
|
||||||
void set_argv(const wcstring_list_t &argv)
|
void set_argv(const wcstring_list_t &argv)
|
||||||
|
|
Loading…
Reference in a new issue