Facilities for turning on new AST-based parser.

This commit is contained in:
ridiculousfish 2013-12-26 13:24:10 -08:00
parent 562946d055
commit 6536ffe178
6 changed files with 100 additions and 25 deletions

View file

@ -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

View file

@ -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);
}

View file

@ -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();
};

View file

@ -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);
}
}

View file

@ -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

View file

@ -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();