mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-13 13:39:02 +00:00
Facilities for turning on new AST-based parser.
This commit is contained in:
parent
562946d055
commit
6536ffe178
6 changed files with 100 additions and 25 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
};
|
||||
|
||||
|
|
65
parser.cpp
65
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);
|
||||
}
|
||||
}
|
||||
|
|
12
parser.h
12
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
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue