diff --git a/Makefile.in b/Makefile.in index 1bca59912..4e01f3d14 100644 --- a/Makefile.in +++ b/Makefile.in @@ -92,7 +92,7 @@ FISH_OBJS := function.o builtin.o complete.o env.o exec.o expand.o \ env_universal.o env_universal_common.o input_common.o event.o \ signal.o io.o parse_util.o common.o screen.o path.o autoload.o \ parser_keywords.o iothread.o color.o postfork.o \ - builtin_test.o parse_tree.o parse_productions.o + builtin_test.o parse_tree.o parse_productions.o parse_execution.cpp FISH_INDENT_OBJS := fish_indent.o print_help.o common.o \ parser_keywords.o wutil.o tokenizer.o diff --git a/parse_execution.cpp b/parse_execution.cpp index 60c0d2627..72ff611cc 100644 --- a/parse_execution.cpp +++ b/parse_execution.cpp @@ -14,7 +14,7 @@ #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), eval_level(0) +parse_execution_context_t::parse_execution_context_t(const parse_node_tree_t &t, const wcstring &s, const io_chain_t &io, parser_t *p) : tree(t), src(s), block_io(io), parser(p), eval_level(0) { } @@ -53,27 +53,27 @@ void parse_execution_context_t::run_while_process(const parse_node_t &header, co assert(header.type == symbol_while_header); assert(statement.type == symbol_block_statement); + /* Push a while block */ while_block_t *wb = new while_block_t(); wb->status = WHILE_TEST_FIRST; wb->node_offset = this->get_offset(statement); parser->push_block(wb); - // The condition of the while loop, as a job + /* The condition and contents of the while loop, as a job and job list respectively */ 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! + /* 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); } + /* Done */ parser->pop_block(wb); } - +/* Appends an error to the error list. Always returns true, so you can assign the result to an 'errored' variable */ bool parse_execution_context_t::append_error(const parse_node_t &node, const wchar_t *fmt, ...) { parse_error_t error; @@ -90,6 +90,7 @@ bool parse_execution_context_t::append_error(const parse_node_t &node, const wch return true; } +/* Creates a 'normal' (non-block) process */ process_t *parse_execution_context_t::create_plain_process(job_t *job, const parse_node_t &statement) { bool errored = false; @@ -529,7 +530,7 @@ int parse_execution_context_t::run_1_job(const parse_node_t &job_node) start_time = get_time(); } - job_t *j = parser->job_create(); + job_t *j = parser->job_create(this->block_io); job_set_flag(j, JOB_FOREGROUND, 1); job_set_flag(j, JOB_TERMINAL, job_get_flag(j, JOB_CONTROL)); job_set_flag(j, JOB_TERMINAL, job_get_flag(j, JOB_CONTROL) \ @@ -597,10 +598,11 @@ int parse_execution_context_t::run_1_job(const parse_node_t &job_node) return ret; } -void parse_execution_context_t::run_job_list(const parse_node_t &job_list_node) +int parse_execution_context_t::run_job_list(const parse_node_t &job_list_node) { assert(job_list_node.type == symbol_job_list); + int result = 1; const parse_node_t *job_list = &job_list_node; while (job_list != NULL) { @@ -631,14 +633,21 @@ void parse_execution_context_t::run_job_list(const parse_node_t &job_list_node) if (job != NULL) { - this->run_1_job(*job); + result = this->run_1_job(*job); } } + /* Returns the last job executed */ + return result; } -void parse_execution_context_t::eval_job_list(const parse_node_t &job_list_node) +int parse_execution_context_t::eval_top_level_job_list() { - this->run_job_list(job_list_node); + if (tree.empty()) + return EXIT_FAILURE; + + const parse_node_t &job_list = tree.at(0); + assert(job_list.type == symbol_job_list); + return this->run_job_list(job_list); } diff --git a/parse_execution.h b/parse_execution.h index f6c7c1207..0d679bb6e 100644 --- a/parse_execution.h +++ b/parse_execution.h @@ -19,6 +19,7 @@ class parse_execution_context_t private: const parse_node_tree_t tree; const wcstring src; + const io_chain_t block_io; parser_t * const parser; parse_error_list_t errors; @@ -53,15 +54,16 @@ class parse_execution_context_t bool determine_io_chain(const parse_node_t &statement, io_chain_t *out_chain); int run_1_job(const parse_node_t &job_node); - void run_job_list(const parse_node_t &job_list_node); + int run_job_list(const parse_node_t &job_list_node); bool populate_job_from_job_node(job_t *j, const parse_node_t &job_node); void eval_next_stack_elem(); public: - parse_execution_context_t(const parse_node_tree_t &t, const wcstring s, parser_t *p); + parse_execution_context_t(const parse_node_tree_t &t, const wcstring &s, const io_chain_t &io, parser_t *p); - void eval_job_list(const parse_node_t &job_node); + /* Actually execute the job list described by the tree */ + int eval_top_level_job_list(); }; diff --git a/parser.cpp b/parser.cpp index adcd22087..da6d9f588 100644 --- a/parser.cpp +++ b/parser.cpp @@ -45,6 +45,7 @@ The fish parser. Contains functions for parsing and evaluating code. #include "signal.h" #include "complete.h" #include "parse_tree.h" +#include "parse_execution.h" /** Maximum number of function calls, i.e. recursion depth. @@ -1189,9 +1190,9 @@ int parser_t::is_help(const wchar_t *s, int min_match) (len >= (size_t)min_match && (wcsncmp(L"--help", s, len) == 0)); } -job_t *parser_t::job_create() +job_t *parser_t::job_create(const io_chain_t &io) { - job_t *res = new job_t(acquire_job_id(), this->block_io); + job_t *res = new job_t(acquire_job_id(), io); this->my_job_list.push_front(res); job_set_flag(res, @@ -2375,7 +2376,7 @@ void parser_t::eval_job(tokenizer_t *tok) { case TOK_STRING: { - job_t *j = this->job_create(); + job_t *j = this->job_create(this->block_io); job_set_flag(j, JOB_FOREGROUND, 1); job_set_flag(j, JOB_TERMINAL, job_get_flag(j, JOB_CONTROL)); job_set_flag(j, JOB_TERMINAL, job_get_flag(j, JOB_CONTROL) \ @@ -2584,9 +2585,55 @@ void parser_t::eval_job(tokenizer_t *tok) job_reap(0); } +int parser_t::eval_new_parser(const wcstring &cmd, const io_chain_t &io, enum block_type_t block_type) +{ + CHECK_BLOCK(1); + + /* 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; + } + + /* Parse the source into a tree, if we can */ + parse_node_tree_t tree; + if (! parse_t::parse(cmd, parse_flag_none, &tree, NULL)) + { + return 1; + } + + /* Not sure why we reap jobs here */ + job_reap(0); + + /* Append to the execution context stack */ + parse_execution_context_t *ctx = new parse_execution_context_t(tree, cmd, io, this); + execution_contexts.push_back(ctx); + + /* Start it up */ + int result = ctx->eval_top_level_job_list(); + + /* Clean up the execution context stack */ + assert(! execution_contexts.empty() && execution_contexts.back() == ctx); + execution_contexts.pop_back(); + delete ctx; + + /* Reap again */ + job_reap(0); + + return result; +} int parser_t::eval(const wcstring &cmd_str, const io_chain_t &io, enum block_type_t block_type) { + + if (parser_use_ast()) + return this->eval_new_parser(cmd_str, io, block_type); + const wchar_t * const cmd = cmd_str.c_str(); size_t forbid_count; int code; @@ -3037,3 +3084,15 @@ breakpoint_block_t::breakpoint_block_t() : { } +bool parser_use_ast(void) +{ + env_var_t var = env_get_string(L"fish_new_parser"); + if (var.missing_or_empty()) + { + return false; + } + else + { + return from_string(var); + } +} diff --git a/parser.h b/parser.h index 80b2303f1..2f9291f03 100644 --- a/parser.h +++ b/parser.h @@ -270,6 +270,7 @@ struct profile_item_t }; struct tokenizer_t; +class parse_execution_context_t; class parser_t { @@ -285,6 +286,9 @@ private: /** Position of last error */ int err_pos; + + /** Stack of execution contexts. We own these pointers and must delete them */ + std::vector execution_contexts; /** Description of last error */ wcstring err_buff; @@ -331,7 +335,7 @@ private: void print_errors_stderr(); /** Create a job */ - job_t *job_create(); + job_t *job_create(const io_chain_t &io); public: std::vector profile_items; @@ -370,7 +374,8 @@ public: \return 0 on success, 1 otherwise */ - int eval(const wcstring &cmdStr, const io_chain_t &io, enum block_type_t block_type); + int eval(const wcstring &cmd_str, const io_chain_t &io, enum block_type_t block_type); + int eval_new_parser(const wcstring &cmd, const io_chain_t &io, enum block_type_t block_type); /** Evaluate line as a list of parameters, i.e. tokenize it and perform parameter expansion and cmdsubst execution on the tokens. @@ -531,5 +536,8 @@ public: const wchar_t *get_block_command(int type) const; }; +/* Temporary */ +bool parser_use_ast(void); + #endif diff --git a/reader.cpp b/reader.cpp index 5186b787d..5c5b094d9 100644 --- a/reader.cpp +++ b/reader.cpp @@ -3398,12 +3398,9 @@ const wchar_t *reader_readline(void) case 0: { /* Finished command, execute it. Don't add items that start with a leading space. */ - if (! data->command_line.empty() && data->command_line.at(0) != L' ') + if (data->history != NULL && ! data->command_line.empty() && data->command_line.at(0) != L' ') { - if (data->history != NULL) - { - data->history->add_with_file_detection(data->command_line); - } + data->history->add_with_file_detection(data->command_line); } finished=1; data->buff_pos=data->command_length();