mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-27 05:13:10 +00:00
Add a convenience method next_node_in_node_list which can be used for
iterating over lists in a parse tree
This commit is contained in:
parent
426f58aa61
commit
45852f0497
3 changed files with 50 additions and 65 deletions
|
@ -73,7 +73,7 @@ const parse_node_t *parse_execution_context_t::infinite_recursive_statement_in_j
|
||||||
const wcstring &forbidden_function_name = parser->forbidden_function.back();
|
const wcstring &forbidden_function_name = parser->forbidden_function.back();
|
||||||
|
|
||||||
/* Get the first job in the job list. */
|
/* Get the first job in the job list. */
|
||||||
const parse_node_t *first_job = tree.next_job_in_job_list(job_list, NULL);
|
const parse_node_t *first_job = tree.next_node_in_node_list(job_list, symbol_job, NULL);
|
||||||
if (first_job == NULL)
|
if (first_job == NULL)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -474,7 +474,9 @@ parse_execution_result_t parse_execution_context_t::run_switch_statement(const p
|
||||||
{
|
{
|
||||||
/* Expand case statements */
|
/* Expand case statements */
|
||||||
const parse_node_t *case_item_list = get_child(statement, 3, symbol_case_item_list);
|
const parse_node_t *case_item_list = get_child(statement, 3, symbol_case_item_list);
|
||||||
while (matching_case_item == NULL && case_item_list->child_count > 0)
|
|
||||||
|
/* Loop while we don't have a match but do have more of the list */
|
||||||
|
while (matching_case_item == NULL && case_item_list != NULL)
|
||||||
{
|
{
|
||||||
if (should_cancel_execution(sb))
|
if (should_cancel_execution(sb))
|
||||||
{
|
{
|
||||||
|
@ -482,18 +484,16 @@ parse_execution_result_t parse_execution_context_t::run_switch_statement(const p
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (case_item_list->production_idx == 2)
|
/* Get the next item and the remainder of the list */
|
||||||
|
const parse_node_t *case_item = tree.next_node_in_node_list(*case_item_list, symbol_case_item, &case_item_list);
|
||||||
|
if (case_item == NULL)
|
||||||
{
|
{
|
||||||
/* Hackish: blank line */
|
/* No more items */
|
||||||
case_item_list = get_child(*case_item_list, 1, symbol_case_item_list);
|
break;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pull out this case item and the rest of the list */
|
|
||||||
const parse_node_t &case_item = *get_child(*case_item_list, 0, symbol_case_item);
|
|
||||||
|
|
||||||
/* Pull out the argument list */
|
/* Pull out the argument list */
|
||||||
const parse_node_t &arg_list = *get_child(case_item, 1, symbol_argument_list);
|
const parse_node_t &arg_list = *get_child(*case_item, 1, symbol_argument_list);
|
||||||
|
|
||||||
/* Expand arguments. We explicitly ignore unmatched_wildcard. That is, a case item list may have a wildcard that fails to expand to anything. */
|
/* Expand arguments. We explicitly ignore unmatched_wildcard. That is, a case item list may have a wildcard that fails to expand to anything. */
|
||||||
const wcstring_list_t case_args = this->determine_arguments(arg_list, NULL);
|
const wcstring_list_t case_args = this->determine_arguments(arg_list, NULL);
|
||||||
|
@ -510,17 +510,14 @@ parse_execution_result_t parse_execution_context_t::run_switch_statement(const p
|
||||||
/* If this matched, we're done */
|
/* If this matched, we're done */
|
||||||
if (match)
|
if (match)
|
||||||
{
|
{
|
||||||
matching_case_item = &case_item;
|
matching_case_item = case_item;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remainder of the list */
|
|
||||||
case_item_list = get_child(*case_item_list, 1, symbol_case_item_list);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == parse_execution_success && matching_case_item)
|
if (result == parse_execution_success && matching_case_item != NULL)
|
||||||
{
|
{
|
||||||
/* Success, evaluate the job list */
|
/* Success, evaluate the job list */
|
||||||
const parse_node_t *job_list = get_child(*matching_case_item, 3, symbol_job_list);
|
const parse_node_t *job_list = get_child(*matching_case_item, 3, symbol_job_list);
|
||||||
|
@ -1320,29 +1317,8 @@ parse_execution_result_t parse_execution_context_t::run_job_list(const parse_nod
|
||||||
{
|
{
|
||||||
assert(job_list->type == symbol_job_list);
|
assert(job_list->type == symbol_job_list);
|
||||||
|
|
||||||
// These correspond to the three productions of job_list
|
|
||||||
// Try pulling out a job
|
// Try pulling out a job
|
||||||
const parse_node_t *job = NULL;
|
const parse_node_t *job = tree.next_node_in_node_list(*job_list, symbol_job, &job_list);
|
||||||
switch (job_list->production_idx)
|
|
||||||
{
|
|
||||||
case 0: // empty
|
|
||||||
job_list = NULL;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1: //job, job_list
|
|
||||||
job = get_child(*job_list, 0, symbol_job);
|
|
||||||
job_list = get_child(*job_list, 1, symbol_job_list);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2: //blank line, job_list
|
|
||||||
job = NULL;
|
|
||||||
job_list = get_child(*job_list, 1, symbol_job_list);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: //if we get here, it means more productions have been added to job_list, which is bad
|
|
||||||
fprintf(stderr, "Unexpected production in job_list: %lu\n", (unsigned long)job_list->production_idx);
|
|
||||||
PARSER_DIE();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (job != NULL)
|
if (job != NULL)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1465,35 +1465,44 @@ parse_node_tree_t::parse_node_list_t parse_node_tree_t::specific_statements_for_
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const parse_node_t *parse_node_tree_t::next_job_in_job_list(const parse_node_t &top_job_list, const parse_node_t **out_list_tail) const
|
const parse_node_t *parse_node_tree_t::next_node_in_node_list(const parse_node_t &node_list, parse_token_type_t entry_type, const parse_node_t **out_list_tail) const
|
||||||
{
|
{
|
||||||
assert(top_job_list.type == symbol_job_list);
|
parse_token_type_t list_type = node_list.type;
|
||||||
|
|
||||||
/* Our cursor variable */
|
/* Paranoia - it doesn't make sense for a list type to contain itself */
|
||||||
const parse_node_t *job_list = &top_job_list;
|
assert(list_type != entry_type);
|
||||||
|
|
||||||
/* Skip over a run of empty jobs */
|
const parse_node_t *list_cursor = &node_list;
|
||||||
assert(job_list->type == symbol_job_list);
|
const parse_node_t *list_entry = NULL;
|
||||||
while (job_list->production_idx == 2)
|
|
||||||
|
/* Loop while we don't have an item but do have a list. Note that not every node in the list may contain an in item that we care about - e.g. job_list contains blank lines as a production */
|
||||||
|
while (list_entry == NULL && list_cursor != NULL)
|
||||||
{
|
{
|
||||||
job_list = this->get_child(*job_list, 1, symbol_job_list);
|
const parse_node_t *next_cursor = NULL;
|
||||||
|
|
||||||
|
/* Walk through the children */
|
||||||
|
for (size_t i=0; i < list_cursor->child_count; i++)
|
||||||
|
{
|
||||||
|
const parse_node_t *child = this->get_child(*list_cursor, i);
|
||||||
|
if (child->type == entry_type)
|
||||||
|
{
|
||||||
|
/* This is the list entry */
|
||||||
|
list_entry = child;
|
||||||
|
}
|
||||||
|
else if (child->type == list_type)
|
||||||
|
{
|
||||||
|
/* This is the next in the list */
|
||||||
|
next_cursor = child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Go to the next entry, even if it's NULL */
|
||||||
|
list_cursor = next_cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Should now be at production 0 or 1 */
|
/* Return what we got */
|
||||||
assert(job_list->type == symbol_job_list);
|
assert(list_cursor == NULL || list_cursor->type == list_type);
|
||||||
assert(job_list->production_idx == 0 || job_list->production_idx == 1);
|
assert(list_entry == NULL || list_entry->type == entry_type);
|
||||||
|
|
||||||
/* Pull out the job */
|
|
||||||
const parse_node_t *job = NULL;
|
|
||||||
const parse_node_t *list_tail = NULL;
|
|
||||||
if (job_list->production_idx == 1)
|
|
||||||
{
|
|
||||||
job = this->get_child(*job_list, 0, symbol_job);
|
|
||||||
list_tail = this->get_child(*job_list, 1, symbol_job_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return them */
|
|
||||||
if (out_list_tail != NULL)
|
if (out_list_tail != NULL)
|
||||||
*out_list_tail = list_tail;
|
*out_list_tail = list_cursor;
|
||||||
return job;
|
return list_entry;
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,8 +211,8 @@ public:
|
||||||
/* If the given node is a block statement, returns the header node (for_header, while_header, begin_header, or function_header). Otherwise returns NULL */
|
/* If the given node is a block statement, returns the header node (for_header, while_header, begin_header, or function_header). Otherwise returns NULL */
|
||||||
const parse_node_t *header_node_for_block_statement(const parse_node_t &node) const;
|
const parse_node_t *header_node_for_block_statement(const parse_node_t &node) const;
|
||||||
|
|
||||||
/* Given a job list, returns the next job (or NULL), and the tail of the job list. */
|
/* Given a node list (e.g. of type symbol_job_list) and a node type (e.g. symbol_job), return the next element of the given type in that list, and the tail (by reference). Returns NULL if we've exhausted the list. */
|
||||||
const parse_node_t *next_job_in_job_list(const parse_node_t &job_list, const parse_node_t **list_tail) const;
|
const parse_node_t *next_node_in_node_list(const parse_node_t &node_list, parse_token_type_t item_type, const parse_node_t **list_tail) const;
|
||||||
|
|
||||||
/* Given a job, return all of its statements. These are 'specific statements' (e.g. symbol_decorated_statement, not symbol_statement) */
|
/* Given a job, return all of its statements. These are 'specific statements' (e.g. symbol_decorated_statement, not symbol_statement) */
|
||||||
parse_node_list_t specific_statements_for_job(const parse_node_t &job) const;
|
parse_node_list_t specific_statements_for_job(const parse_node_t &job) const;
|
||||||
|
|
Loading…
Reference in a new issue