aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Makefile.in2
-rw-r--r--parse_execution.cpp31
-rw-r--r--parse_execution.h8
-rw-r--r--parser.cpp65
-rw-r--r--parser.h12
-rw-r--r--reader.cpp7
6 files changed, 100 insertions, 25 deletions
diff --git a/Makefile.in b/Makefile.in
index 1bca5991..4e01f3d1 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 60c0d262..72ff611c 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 f6c7c120..0d679bb6 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 adcd2208..da6d9f58 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<bool>(var);
+ }
+}
diff --git a/parser.h b/parser.h
index 80b2303f..2f9291f0 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<parse_execution_context_t *> 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_item_t*> 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 5186b787..5c5b094d 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();