mirror of
https://github.com/fish-shell/fish-shell
synced 2024-11-11 23:47:25 +00:00
Allow parse_execution_context to take ownership of a parse tree
Introduces a new template moved_ref which is like an rvalue reference. This allows passing around objects while being explicit that the receiver may acquire ownership. This will help reduce some allocations.
This commit is contained in:
parent
077757a30b
commit
e3970f9cbb
7 changed files with 45 additions and 35 deletions
11
src/common.h
11
src/common.h
|
@ -450,6 +450,17 @@ inline wcstring to_string(const int &x)
|
||||||
return to_string(static_cast<long>(x));
|
return to_string(static_cast<long>(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A hackish thing to simulate rvalue references in C++98.
|
||||||
|
The idea is that you can define a constructor to take a moved_ref<T> and then swap() out of it.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
struct moved_ref
|
||||||
|
{
|
||||||
|
T &val;
|
||||||
|
|
||||||
|
explicit moved_ref(T &v) : val(v) { }
|
||||||
|
};
|
||||||
|
|
||||||
wchar_t **make_null_terminated_array(const wcstring_list_t &lst);
|
wchar_t **make_null_terminated_array(const wcstring_list_t &lst);
|
||||||
char **make_null_terminated_array(const std::vector<std::string> &lst);
|
char **make_null_terminated_array(const std::vector<std::string> &lst);
|
||||||
|
|
||||||
|
|
|
@ -751,17 +751,6 @@ static void test_parser()
|
||||||
}
|
}
|
||||||
|
|
||||||
say(L"Testing basic evaluation");
|
say(L"Testing basic evaluation");
|
||||||
#if 0
|
|
||||||
/* This fails now since the parser takes a wcstring&, and NULL converts to wchar_t * converts to wcstring which crashes (thanks C++) */
|
|
||||||
if (!parser.eval(0, 0, TOP))
|
|
||||||
{
|
|
||||||
err(L"Null input when evaluating undetected");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (!parser.eval(L"ls", io_chain_t(), WHILE))
|
|
||||||
{
|
|
||||||
err(L"Invalid block mode when evaluating undetected");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ensure that we don't crash on infinite self recursion and mutual recursion. These must use the principal parser because we cannot yet execute jobs on other parsers (!) */
|
/* Ensure that we don't crash on infinite self recursion and mutual recursion. These must use the principal parser because we cannot yet execute jobs on other parsers (!) */
|
||||||
say(L"Testing recursion detection");
|
say(L"Testing recursion detection");
|
||||||
|
|
|
@ -66,7 +66,7 @@ static wcstring profiling_cmd_name_for_redirectable_block(const parse_node_t &no
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_execution_context_t::parse_execution_context_t(const parse_node_tree_t &t, const wcstring &s, parser_t *p, int initial_eval_level) : tree(t), src(s), parser(p), eval_level(initial_eval_level), executing_node_idx(NODE_OFFSET_INVALID), cached_lineno_offset(0), cached_lineno_count(0)
|
parse_execution_context_t::parse_execution_context_t(moved_ref<parse_node_tree_t> t, const wcstring &s, parser_t *p, int initial_eval_level) : tree(t), src(s), parser(p), eval_level(initial_eval_level), executing_node_idx(NODE_OFFSET_INVALID), cached_lineno_offset(0), cached_lineno_count(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -121,7 +121,7 @@ private:
|
||||||
int line_offset_of_character_at_offset(size_t char_idx);
|
int line_offset_of_character_at_offset(size_t char_idx);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
parse_execution_context_t(const parse_node_tree_t &t, const wcstring &s, parser_t *p, int initial_eval_level);
|
parse_execution_context_t(moved_ref<parse_node_tree_t> t, const wcstring &s, parser_t *p, int initial_eval_level);
|
||||||
|
|
||||||
/* Returns the current eval level */
|
/* Returns the current eval level */
|
||||||
int current_eval_level() const
|
int current_eval_level() const
|
||||||
|
|
|
@ -166,6 +166,13 @@ class parse_node_tree_t : public std::vector<parse_node_t>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
parse_node_tree_t() {}
|
||||||
|
|
||||||
|
parse_node_tree_t(moved_ref<parse_node_tree_t> t)
|
||||||
|
{
|
||||||
|
this->swap(t.val);
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the node corresponding to a child of the given node, or NULL if there is no such child. If expected_type is provided, assert that the node has that type.
|
/* Get the node corresponding to a child of the given node, or NULL if there is no such child. If expected_type is provided, assert that the node has that type.
|
||||||
*/
|
*/
|
||||||
const parse_node_t *get_child(const parse_node_t &parent, node_offset_t which, parse_token_type_t expected_type = token_type_invalid) const;
|
const parse_node_t *get_child(const parse_node_t &parent, node_offset_t which, parse_token_type_t expected_type = token_type_invalid) const;
|
||||||
|
|
|
@ -813,18 +813,8 @@ profile_item_t *parser_t::create_profile_item()
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int parser_t::eval(const wcstring &cmd, const io_chain_t &io, enum block_type_t block_type)
|
int parser_t::eval(const wcstring &cmd, const io_chain_t &io, enum block_type_t block_type)
|
||||||
{
|
{
|
||||||
CHECK_BLOCK(1);
|
|
||||||
|
|
||||||
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 the source into a tree, if we can */
|
||||||
parse_node_tree_t tree;
|
parse_node_tree_t tree;
|
||||||
parse_error_list_t error_list;
|
parse_error_list_t error_list;
|
||||||
|
@ -839,10 +829,21 @@ int parser_t::eval(const wcstring &cmd, const io_chain_t &io, enum block_type_t
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
return this->eval_acquiring_tree(cmd, io, block_type, moved_ref<parse_node_tree_t>(tree));
|
||||||
|
}
|
||||||
|
|
||||||
|
int parser_t::eval_acquiring_tree(const wcstring &cmd, const io_chain_t &io, enum block_type_t block_type, moved_ref<parse_node_tree_t> tree)
|
||||||
|
{
|
||||||
|
CHECK_BLOCK(1);
|
||||||
|
assert(block_type == TOP || block_type == SUBST);
|
||||||
|
|
||||||
|
if (tree.val.empty())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
//print_stderr(block_stack_description());
|
//print_stderr(block_stack_description());
|
||||||
|
|
||||||
|
|
||||||
/* Determine the initial eval level. If this is the first context, it's -1; otherwise it's the eval level of the top context. This is sort of wonky because we're stitching together a global notion of eval level from these separate objects. A better approach would be some profile object that all contexts share, and that tracks the eval levels on its own. */
|
/* Determine the initial eval level. If this is the first context, it's -1; otherwise it's the eval level of the top context. This is sort of wonky because we're stitching together a global notion of eval level from these separate objects. A better approach would be some profile object that all contexts share, and that tracks the eval levels on its own. */
|
||||||
int exec_eval_level = (execution_contexts.empty() ? -1 : execution_contexts.back()->current_eval_level());
|
int exec_eval_level = (execution_contexts.empty() ? -1 : execution_contexts.back()->current_eval_level());
|
||||||
|
|
||||||
|
@ -851,10 +852,7 @@ int parser_t::eval(const wcstring &cmd, const io_chain_t &io, enum block_type_t
|
||||||
execution_contexts.push_back(ctx);
|
execution_contexts.push_back(ctx);
|
||||||
|
|
||||||
/* Execute the first node */
|
/* Execute the first node */
|
||||||
if (! tree.empty())
|
this->eval_block_node(0, io, block_type);
|
||||||
{
|
|
||||||
this->eval_block_node(0, io, block_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clean up the execution context stack */
|
/* Clean up the execution context stack */
|
||||||
assert(! execution_contexts.empty() && execution_contexts.back() == ctx);
|
assert(! execution_contexts.empty() && execution_contexts.back() == ctx);
|
||||||
|
|
|
@ -297,6 +297,11 @@ public:
|
||||||
*/
|
*/
|
||||||
int eval(const wcstring &cmd, const io_chain_t &io, enum block_type_t block_type);
|
int eval(const wcstring &cmd, const io_chain_t &io, enum block_type_t block_type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Evaluate the expressions contained in cmd, which has been parsed into the given parse tree. This takes ownership of the tree.
|
||||||
|
*/
|
||||||
|
int eval_acquiring_tree(const wcstring &cmd, const io_chain_t &io, enum block_type_t block_type, moved_ref<parse_node_tree_t> t);
|
||||||
|
|
||||||
/** Evaluates a block node at the given node offset in the topmost execution context */
|
/** Evaluates a block node at the given node offset in the topmost execution context */
|
||||||
int eval_block_node(node_offset_t node_idx, const io_chain_t &io, enum block_type_t block_type);
|
int eval_block_node(node_offset_t node_idx, const io_chain_t &io, enum block_type_t block_type);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue