mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-26 12:53:13 +00:00
Implement support for switch
This commit is contained in:
parent
eba5b0e4c5
commit
70b83a3bbb
5 changed files with 298 additions and 30 deletions
10
builtin.cpp
10
builtin.cpp
|
@ -3983,11 +3983,11 @@ struct parse_execution_simulator_t : public parse_execution_visitor_t
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void enter_if_header(const if_header_t &statement)
|
virtual void enter_if_clause(const exec_if_clause_t &statement)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void exit_if_header(const if_header_t &statement)
|
virtual void exit_if_clause(const exec_if_clause_t &statement)
|
||||||
{
|
{
|
||||||
append_format(back(), L"\nIF successful jump to %lu", (unsigned long)statement.body);
|
append_format(back(), L"\nIF successful jump to %lu", (unsigned long)statement.body);
|
||||||
}
|
}
|
||||||
|
@ -4041,6 +4041,12 @@ struct parse_execution_simulator_t : public parse_execution_visitor_t
|
||||||
|
|
||||||
int builtin_parse(parser_t &parser, wchar_t **argv)
|
int builtin_parse(parser_t &parser, wchar_t **argv)
|
||||||
{
|
{
|
||||||
|
struct sigaction act;
|
||||||
|
sigemptyset(& act.sa_mask);
|
||||||
|
act.sa_flags=0;
|
||||||
|
act.sa_handler=SIG_DFL;
|
||||||
|
sigaction(SIGINT, &act, 0);
|
||||||
|
|
||||||
std::vector<char> txt;
|
std::vector<char> txt;
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
|
172
parse_exec.cpp
172
parse_exec.cpp
|
@ -36,7 +36,7 @@ class parse_exec_t
|
||||||
/* Current visitor (very transient) */
|
/* Current visitor (very transient) */
|
||||||
struct parse_execution_visitor_t * visitor;
|
struct parse_execution_visitor_t * visitor;
|
||||||
|
|
||||||
const parse_node_t &get_child(parse_node_t &parent, node_offset_t which) const
|
const parse_node_t &get_child(const parse_node_t &parent, node_offset_t which) const
|
||||||
{
|
{
|
||||||
return parse_tree.at(parent.child_offset(which));
|
return parse_tree.at(parent.child_offset(which));
|
||||||
}
|
}
|
||||||
|
@ -214,6 +214,118 @@ class parse_exec_t
|
||||||
push(exec_node_t(header_idx, body_idx));
|
push(exec_node_t(header_idx, body_idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* which: 0 -> if, 1 -> else if, 2 -> else */
|
||||||
|
void assemble_if_else_clause(exec_node_t &exec_node, const parse_node_t &node, int which)
|
||||||
|
{
|
||||||
|
if (which == 0)
|
||||||
|
{
|
||||||
|
PARSE_ASSERT(node.type == symbol_if_clause);
|
||||||
|
PARSE_ASSERT(node.child_count == 4);
|
||||||
|
}
|
||||||
|
else if (which == 2)
|
||||||
|
{
|
||||||
|
PARSE_ASSERT(node.type == symbol_else_continuation);
|
||||||
|
PARSE_ASSERT(node.child_count == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct exec_if_clause_t clause;
|
||||||
|
if (which == 0)
|
||||||
|
{
|
||||||
|
clause.body = node.child_offset(3);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clause.body = node.child_offset(1);
|
||||||
|
}
|
||||||
|
if (! exec_node.visited)
|
||||||
|
{
|
||||||
|
visitor->enter_if_clause(clause);
|
||||||
|
exec_node.visited = true;
|
||||||
|
if (which == 0)
|
||||||
|
{
|
||||||
|
push(node.child_offset(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
visitor->exit_if_clause(clause);
|
||||||
|
pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void assemble_arguments(node_offset_t start_idx, exec_argument_list_t *output) const
|
||||||
|
{
|
||||||
|
node_offset_t idx = start_idx;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const parse_node_t &node = parse_tree.at(idx);
|
||||||
|
PARSE_ASSERT(node.type == symbol_argument_list || node.type == symbol_argument_list_nonempty);
|
||||||
|
if (node.type == symbol_argument_list)
|
||||||
|
{
|
||||||
|
// argument list, may be empty
|
||||||
|
PARSE_ASSERT(node.child_count == 0 || node.child_count == 1);
|
||||||
|
if (node.child_count == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
idx = node.child_offset(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// nonempty argument list
|
||||||
|
PARSE_ASSERT(node.child_count == 2);
|
||||||
|
output->push_back(exec_argument_t(node.child_offset(0)));
|
||||||
|
idx = node.child_offset(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void assemble_1_case_item(exec_switch_statement_t *statement, node_offset_t node_idx)
|
||||||
|
{
|
||||||
|
const parse_node_t &node = parse_tree.at(node_idx);
|
||||||
|
PARSE_ASSERT(node.type == symbol_case_item);
|
||||||
|
|
||||||
|
// add a new case
|
||||||
|
size_t len = statement->cases.size();
|
||||||
|
statement->cases.resize(len + 1);
|
||||||
|
exec_switch_case_t &new_case = statement->cases.back();
|
||||||
|
|
||||||
|
// assemble it
|
||||||
|
new_case.body = node.child_offset(3);
|
||||||
|
assemble_arguments(node.child_offset(1), &new_case.arguments);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void assemble_case_item_list(exec_switch_statement_t *statement, node_offset_t node_idx)
|
||||||
|
{
|
||||||
|
const parse_node_t &node = parse_tree.at(node_idx);
|
||||||
|
PARSE_ASSERT(node.type == symbol_case_item_list);
|
||||||
|
PARSE_ASSERT(node.child_count == 0 || node.child_count == 2);
|
||||||
|
if (node.child_count == 2)
|
||||||
|
{
|
||||||
|
assemble_1_case_item(statement, node.child_offset(0));
|
||||||
|
assemble_case_item_list(statement, node.child_offset(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void assemble_switch_statement(const exec_node_t &exec_node, const parse_node_t &parse_node)
|
||||||
|
{
|
||||||
|
PARSE_ASSERT(parse_node.type == symbol_switch_statement);
|
||||||
|
exec_switch_statement_t statement;
|
||||||
|
|
||||||
|
statement.argument.parse_node_idx = parse_node.child_offset(1);
|
||||||
|
assemble_case_item_list(&statement, parse_node.child_offset(3));
|
||||||
|
|
||||||
|
visitor->visit_switch_statement(statement);
|
||||||
|
|
||||||
|
// pop off the switch
|
||||||
|
pop();
|
||||||
|
}
|
||||||
|
|
||||||
void assemble_function_header(const exec_node_t &exec_node, const parse_node_t &header)
|
void assemble_function_header(const exec_node_t &exec_node, const parse_node_t &header)
|
||||||
{
|
{
|
||||||
PARSE_ASSERT(header.type == symbol_function_header);
|
PARSE_ASSERT(header.type == symbol_function_header);
|
||||||
|
@ -222,7 +334,7 @@ class parse_exec_t
|
||||||
exec_function_header_t function_info;
|
exec_function_header_t function_info;
|
||||||
function_info.name_idx = header.child_offset(1);
|
function_info.name_idx = header.child_offset(1);
|
||||||
function_info.body_idx = exec_node.body_parse_node_idx;
|
function_info.body_idx = exec_node.body_parse_node_idx;
|
||||||
assemble_arguments_and_redirections(header.child_offset(2), &function_info.arguments_and_redirections);
|
assemble_arguments(header.child_offset(2), &function_info.arguments);
|
||||||
visitor->visit_function(function_info);
|
visitor->visit_function(function_info);
|
||||||
|
|
||||||
// Always pop
|
// Always pop
|
||||||
|
@ -347,10 +459,59 @@ void parse_exec_t::run_top_node()
|
||||||
case symbol_if_statement:
|
case symbol_if_statement:
|
||||||
{
|
{
|
||||||
PARSE_ASSERT(parse_node.child_count == 3);
|
PARSE_ASSERT(parse_node.child_count == 3);
|
||||||
|
pop_push(0, 2);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case symbol_if_clause:
|
||||||
|
{
|
||||||
|
PARSE_ASSERT(parse_node.child_count == 4);
|
||||||
|
assemble_if_else_clause(exec_node, parse_node, 0);
|
||||||
|
pop();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case symbol_else_clause:
|
||||||
|
{
|
||||||
|
PARSE_ASSERT(parse_node.child_count == 0 || parse_node.child_count == 2);
|
||||||
|
if (parse_node.child_count == 0)
|
||||||
|
{
|
||||||
|
// No else
|
||||||
|
pop();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We have an else
|
||||||
|
pop_push(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case symbol_else_continuation:
|
||||||
|
{
|
||||||
|
// Figure out if this is an else if or a terminating else
|
||||||
|
PARSE_ASSERT(parse_node.child_count == 2);
|
||||||
|
const parse_node_t &first_child = get_child(parse_node, 1);
|
||||||
|
PARSE_ASSERT(first_child.type == symbol_if_clause || first_child.type == parse_token_type_end);
|
||||||
|
if (first_child.type == symbol_if_clause)
|
||||||
|
{
|
||||||
|
pop_push_all();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// else
|
||||||
|
assemble_if_else_clause(exec_node, parse_node, 2);
|
||||||
|
pop();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case symbol_switch_statement:
|
||||||
|
{
|
||||||
|
assemble_switch_statement(exec_node, parse_node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case symbol_decorated_statement:
|
case symbol_decorated_statement:
|
||||||
{
|
{
|
||||||
PARSE_ASSERT(parse_node.child_count == 1 || parse_node.child_count == 2);
|
PARSE_ASSERT(parse_node.child_count == 1 || parse_node.child_count == 2);
|
||||||
|
@ -363,6 +524,7 @@ void parse_exec_t::run_top_node()
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following symbols should be handled by their parents, i.e. never pushed on our stack
|
// The following symbols should be handled by their parents, i.e. never pushed on our stack
|
||||||
|
case symbol_case_item_list:
|
||||||
case symbol_plain_statement:
|
case symbol_plain_statement:
|
||||||
case symbol_arguments_or_redirections_list:
|
case symbol_arguments_or_redirections_list:
|
||||||
case symbol_argument_or_redirection:
|
case symbol_argument_or_redirection:
|
||||||
|
|
29
parse_exec.h
29
parse_exec.h
|
@ -28,6 +28,12 @@ class parse_execution_context_t
|
||||||
struct exec_argument_t
|
struct exec_argument_t
|
||||||
{
|
{
|
||||||
node_offset_t parse_node_idx;
|
node_offset_t parse_node_idx;
|
||||||
|
exec_argument_t(node_offset_t p) : parse_node_idx(p)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
exec_argument_t()
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
typedef std::vector<exec_argument_t> exec_argument_list_t;
|
typedef std::vector<exec_argument_t> exec_argument_list_t;
|
||||||
|
|
||||||
|
@ -101,7 +107,7 @@ struct exec_function_header_t
|
||||||
node_offset_t body_idx;
|
node_offset_t body_idx;
|
||||||
|
|
||||||
// Arguments
|
// Arguments
|
||||||
exec_arguments_and_redirections_t arguments_and_redirections;
|
exec_argument_list_t arguments;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct exec_block_statement_t
|
struct exec_block_statement_t
|
||||||
|
@ -110,12 +116,24 @@ struct exec_block_statement_t
|
||||||
exec_arguments_and_redirections_t arguments_and_redirections;
|
exec_arguments_and_redirections_t arguments_and_redirections;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct if_header_t
|
struct exec_if_clause_t
|
||||||
{
|
{
|
||||||
// Node containing the body of the if statement
|
// Node containing the body of the if statement
|
||||||
node_offset_t body;
|
node_offset_t body;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct exec_switch_case_t
|
||||||
|
{
|
||||||
|
exec_argument_list_t arguments;
|
||||||
|
node_offset_t body;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct exec_switch_statement_t
|
||||||
|
{
|
||||||
|
exec_argument_t argument;
|
||||||
|
std::vector<exec_switch_case_t> cases;
|
||||||
|
};
|
||||||
|
|
||||||
struct parse_execution_visitor_t
|
struct parse_execution_visitor_t
|
||||||
{
|
{
|
||||||
node_offset_t node_idx;
|
node_offset_t node_idx;
|
||||||
|
@ -131,8 +149,11 @@ struct parse_execution_visitor_t
|
||||||
virtual void visit_function(const exec_function_header_t &function) { }
|
virtual void visit_function(const exec_function_header_t &function) { }
|
||||||
virtual bool enter_block_statement(const exec_block_statement_t &statement) { return true; }
|
virtual bool enter_block_statement(const exec_block_statement_t &statement) { return true; }
|
||||||
|
|
||||||
virtual void enter_if_header(const if_header_t &statement) { }
|
virtual void enter_if_clause(const exec_if_clause_t &statement) { }
|
||||||
virtual void exit_if_header(const if_header_t &statement) { }
|
virtual void exit_if_clause(const exec_if_clause_t &statement) { }
|
||||||
|
|
||||||
|
virtual void visit_switch_statement(const exec_switch_statement_t &header) { }
|
||||||
|
|
||||||
|
|
||||||
virtual void visit_boolean_statement(void) { }
|
virtual void visit_boolean_statement(void) { }
|
||||||
virtual void visit_basic_statement(const exec_basic_statement_t &statement) { }
|
virtual void visit_basic_statement(const exec_basic_statement_t &statement) { }
|
||||||
|
|
|
@ -61,6 +61,13 @@ wcstring token_type_description(parse_token_type_t type)
|
||||||
case symbol_else_clause: return L"else_clause";
|
case symbol_else_clause: return L"else_clause";
|
||||||
case symbol_else_continuation: return L"else_continuation";
|
case symbol_else_continuation: return L"else_continuation";
|
||||||
|
|
||||||
|
case symbol_switch_statement: return L"switch_statement";
|
||||||
|
case symbol_case_item_list: return L"case_item_list";
|
||||||
|
case symbol_case_item: return L"case_item";
|
||||||
|
|
||||||
|
case symbol_argument_list_nonempty: return L"argument_list_nonempty";
|
||||||
|
case symbol_argument_list: return L"argument_list";
|
||||||
|
|
||||||
case symbol_boolean_statement: return L"boolean_statement";
|
case symbol_boolean_statement: return L"boolean_statement";
|
||||||
case symbol_decorated_statement: return L"decorated_statement";
|
case symbol_decorated_statement: return L"decorated_statement";
|
||||||
case symbol_plain_statement: return L"plain_statement";
|
case symbol_plain_statement: return L"plain_statement";
|
||||||
|
@ -263,8 +270,10 @@ class parse_ll_t
|
||||||
void accept_token_else_clause(parse_token_t token);
|
void accept_token_else_clause(parse_token_t token);
|
||||||
void accept_token_else_continuation(parse_token_t token);
|
void accept_token_else_continuation(parse_token_t token);
|
||||||
void accept_token_boolean_statement(parse_token_t token);
|
void accept_token_boolean_statement(parse_token_t token);
|
||||||
|
void accept_token_case_item_list(parse_token_t token);
|
||||||
void accept_token_decorated_statement(parse_token_t token);
|
void accept_token_decorated_statement(parse_token_t token);
|
||||||
void accept_token_plain_statement(parse_token_t token);
|
void accept_token_plain_statement(parse_token_t token);
|
||||||
|
void accept_token_argument_list(parse_token_t token);
|
||||||
void accept_token_arguments_or_redirections_list(parse_token_t token);
|
void accept_token_arguments_or_redirections_list(parse_token_t token);
|
||||||
void accept_token_argument_or_redirection(parse_token_t token);
|
void accept_token_argument_or_redirection(parse_token_t token);
|
||||||
bool accept_token_string(parse_token_t token);
|
bool accept_token_string(parse_token_t token);
|
||||||
|
@ -312,7 +321,7 @@ class parse_ll_t
|
||||||
// Logging?
|
// Logging?
|
||||||
if (1)
|
if (1)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Pop %ls\n", token_type_description(symbol_stack.back().type).c_str());
|
fprintf(stderr, "Pop %ls (%lu)\n", token_type_description(symbol_stack.back().type).c_str(), symbol_stack.size());
|
||||||
if (tok5.type != token_type_invalid) fprintf(stderr, "Push %ls\n", tok5.describe().c_str());
|
if (tok5.type != token_type_invalid) fprintf(stderr, "Push %ls\n", tok5.describe().c_str());
|
||||||
if (tok4.type != token_type_invalid) fprintf(stderr, "Push %ls\n", tok4.describe().c_str());
|
if (tok4.type != token_type_invalid) fprintf(stderr, "Push %ls\n", tok4.describe().c_str());
|
||||||
if (tok3.type != token_type_invalid) fprintf(stderr, "Push %ls\n", tok3.describe().c_str());
|
if (tok3.type != token_type_invalid) fprintf(stderr, "Push %ls\n", tok3.describe().c_str());
|
||||||
|
@ -404,15 +413,18 @@ void parse_ll_t::accept_token_job_list(parse_token_t token)
|
||||||
{
|
{
|
||||||
case parse_token_type_string:
|
case parse_token_type_string:
|
||||||
// 'end' is special
|
// 'end' is special
|
||||||
if (token.keyword == parse_keyword_end)
|
switch (token.keyword)
|
||||||
{
|
{
|
||||||
// End this job list
|
case parse_keyword_end:
|
||||||
symbol_stack_pop_push();
|
case parse_keyword_else:
|
||||||
}
|
// End this job list
|
||||||
else
|
symbol_stack_pop_push();
|
||||||
{
|
break;
|
||||||
// Normal string
|
|
||||||
symbol_stack_pop_push(symbol_job, symbol_job_list);
|
default:
|
||||||
|
// Normal string
|
||||||
|
symbol_stack_pop_push(symbol_job, symbol_job_list);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -487,10 +499,11 @@ void parse_ll_t::accept_token_statement(parse_token_t token)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case parse_keyword_else:
|
case parse_keyword_else:
|
||||||
|
symbol_stack_pop_push();
|
||||||
|
break;
|
||||||
|
|
||||||
case parse_keyword_switch:
|
case parse_keyword_switch:
|
||||||
symbol_stack_pop_push(symbol_block_statement);
|
symbol_stack_pop_push(symbol_switch_statement);
|
||||||
fprintf(stderr, "Unimplemented type\n");
|
|
||||||
PARSER_DIE();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case parse_keyword_end:
|
case parse_keyword_end:
|
||||||
|
@ -502,6 +515,7 @@ void parse_ll_t::accept_token_statement(parse_token_t token)
|
||||||
case parse_keyword_none:
|
case parse_keyword_none:
|
||||||
case parse_keyword_command:
|
case parse_keyword_command:
|
||||||
case parse_keyword_builtin:
|
case parse_keyword_builtin:
|
||||||
|
case parse_keyword_case:
|
||||||
symbol_stack_pop_push(symbol_decorated_statement);
|
symbol_stack_pop_push(symbol_decorated_statement);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -612,6 +626,7 @@ void parse_ll_t::accept_token_boolean_statement(parse_token_t token)
|
||||||
token_unhandled(token, __FUNCTION__);
|
token_unhandled(token, __FUNCTION__);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
token_unhandled(token, __FUNCTION__);
|
token_unhandled(token, __FUNCTION__);
|
||||||
|
@ -619,6 +634,22 @@ void parse_ll_t::accept_token_boolean_statement(parse_token_t token)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void parse_ll_t::accept_token_case_item_list(parse_token_t token)
|
||||||
|
{
|
||||||
|
PARSE_ASSERT(stack_top_type() == symbol_case_item_list);
|
||||||
|
switch (token.keyword)
|
||||||
|
{
|
||||||
|
case parse_keyword_case:
|
||||||
|
symbol_stack_pop_push(symbol_case_item, symbol_case_item_list);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// empty list
|
||||||
|
symbol_stack_pop_push();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void parse_ll_t::accept_token_decorated_statement(parse_token_t token)
|
void parse_ll_t::accept_token_decorated_statement(parse_token_t token)
|
||||||
{
|
{
|
||||||
PARSE_ASSERT(stack_top_type() == symbol_decorated_statement);
|
PARSE_ASSERT(stack_top_type() == symbol_decorated_statement);
|
||||||
|
@ -656,6 +687,20 @@ void parse_ll_t::accept_token_plain_statement(parse_token_t token)
|
||||||
symbol_stack_pop_push(parse_token_type_string, symbol_arguments_or_redirections_list);
|
symbol_stack_pop_push(parse_token_type_string, symbol_arguments_or_redirections_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void parse_ll_t::accept_token_argument_list(parse_token_t token)
|
||||||
|
{
|
||||||
|
PARSE_ASSERT(stack_top_type() == symbol_argument_list);
|
||||||
|
if (token.type == parse_token_type_string)
|
||||||
|
{
|
||||||
|
symbol_stack_pop_push(symbol_argument_list_nonempty);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
symbol_stack_pop_push();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void parse_ll_t::accept_token_arguments_or_redirections_list(parse_token_t token)
|
void parse_ll_t::accept_token_arguments_or_redirections_list(parse_token_t token)
|
||||||
{
|
{
|
||||||
PARSE_ASSERT(stack_top_type() == symbol_arguments_or_redirections_list);
|
PARSE_ASSERT(stack_top_type() == symbol_arguments_or_redirections_list);
|
||||||
|
@ -822,7 +867,19 @@ void parse_ll_t::accept_token(parse_token_t token, const wcstring &src)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case symbol_function_header:
|
case symbol_function_header:
|
||||||
symbol_stack_pop_push(parse_keyword_function, parse_token_type_string, symbol_arguments_or_redirections_list);
|
symbol_stack_pop_push(parse_keyword_function, parse_token_type_string, symbol_argument_list);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case symbol_switch_statement:
|
||||||
|
symbol_stack_pop_push(parse_keyword_switch, parse_token_type_string, parse_token_type_end, symbol_case_item_list, parse_keyword_end);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case symbol_case_item_list:
|
||||||
|
accept_token_case_item_list(token);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case symbol_case_item:
|
||||||
|
symbol_stack_pop_push(parse_keyword_case, symbol_argument_list, parse_token_type_end, symbol_job_list);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case symbol_boolean_statement:
|
case symbol_boolean_statement:
|
||||||
|
@ -837,6 +894,14 @@ void parse_ll_t::accept_token(parse_token_t token, const wcstring &src)
|
||||||
accept_token_plain_statement(token);
|
accept_token_plain_statement(token);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case symbol_argument_list_nonempty:
|
||||||
|
symbol_stack_pop_push(parse_token_type_string, symbol_argument_list);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case symbol_argument_list:
|
||||||
|
accept_token_argument_list(token);
|
||||||
|
break;
|
||||||
|
|
||||||
case symbol_arguments_or_redirections_list:
|
case symbol_arguments_or_redirections_list:
|
||||||
accept_token_arguments_or_redirections_list(token);
|
accept_token_arguments_or_redirections_list(token);
|
||||||
break;
|
break;
|
||||||
|
@ -844,7 +909,7 @@ void parse_ll_t::accept_token(parse_token_t token, const wcstring &src)
|
||||||
case symbol_argument_or_redirection:
|
case symbol_argument_or_redirection:
|
||||||
accept_token_argument_or_redirection(token);
|
accept_token_argument_or_redirection(token);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Tokens */
|
/* Tokens */
|
||||||
case parse_token_type_string:
|
case parse_token_type_string:
|
||||||
consumed = accept_token_string(token);
|
consumed = accept_token_string(token);
|
||||||
|
@ -880,6 +945,7 @@ static parse_keyword_t keyword_for_token(token_type tok, const wchar_t *tok_txt)
|
||||||
{L"begin", parse_keyword_begin},
|
{L"begin", parse_keyword_begin},
|
||||||
{L"function", parse_keyword_function},
|
{L"function", parse_keyword_function},
|
||||||
{L"switch", parse_keyword_switch},
|
{L"switch", parse_keyword_switch},
|
||||||
|
{L"case", parse_keyword_case},
|
||||||
{L"end", parse_keyword_end},
|
{L"end", parse_keyword_end},
|
||||||
{L"and", parse_keyword_and},
|
{L"and", parse_keyword_and},
|
||||||
{L"or", parse_keyword_or},
|
{L"or", parse_keyword_or},
|
||||||
|
|
23
parse_tree.h
23
parse_tree.h
|
@ -68,11 +68,18 @@ enum parse_token_type_t
|
||||||
symbol_else_clause,
|
symbol_else_clause,
|
||||||
symbol_else_continuation,
|
symbol_else_continuation,
|
||||||
|
|
||||||
|
symbol_switch_statement,
|
||||||
|
symbol_case_item_list,
|
||||||
|
symbol_case_item,
|
||||||
|
|
||||||
symbol_boolean_statement,
|
symbol_boolean_statement,
|
||||||
symbol_decorated_statement,
|
symbol_decorated_statement,
|
||||||
symbol_plain_statement,
|
symbol_plain_statement,
|
||||||
symbol_arguments_or_redirections_list,
|
symbol_arguments_or_redirections_list,
|
||||||
symbol_argument_or_redirection,
|
symbol_argument_or_redirection,
|
||||||
|
|
||||||
|
symbol_argument_list_nonempty,
|
||||||
|
symbol_argument_list,
|
||||||
|
|
||||||
// Terminal types
|
// Terminal types
|
||||||
parse_token_type_string,
|
parse_token_type_string,
|
||||||
|
@ -96,6 +103,7 @@ enum parse_keyword_t
|
||||||
parse_keyword_begin,
|
parse_keyword_begin,
|
||||||
parse_keyword_function,
|
parse_keyword_function,
|
||||||
parse_keyword_switch,
|
parse_keyword_switch,
|
||||||
|
parse_keyword_case,
|
||||||
parse_keyword_end,
|
parse_keyword_end,
|
||||||
parse_keyword_and,
|
parse_keyword_and,
|
||||||
parse_keyword_or,
|
parse_keyword_or,
|
||||||
|
@ -164,7 +172,7 @@ class parse_node_tree_t : public std::vector<parse_node_t>
|
||||||
|
|
||||||
# A statement is a normal command, or an if / while / and etc
|
# A statement is a normal command, or an if / while / and etc
|
||||||
|
|
||||||
statement = boolean_statement | block_statement | if_statement | decorated_statement
|
statement = boolean_statement | block_statement | if_statement | switch_statement | decorated_statement
|
||||||
|
|
||||||
# A block is a conditional, loop, or begin/end
|
# A block is a conditional, loop, or begin/end
|
||||||
|
|
||||||
|
@ -174,16 +182,21 @@ class parse_node_tree_t : public std::vector<parse_node_t>
|
||||||
<ELSE> else_continuation
|
<ELSE> else_continuation
|
||||||
else_continuation = if_clause else_clause |
|
else_continuation = if_clause else_clause |
|
||||||
STATEMENT_TERMINATOR job_list
|
STATEMENT_TERMINATOR job_list
|
||||||
|
|
||||||
|
switch_statement = SWITCH <TOK_STRING> STATEMENT_TERMINATOR case_item_list <END>
|
||||||
|
case_item_list = <empty> |
|
||||||
|
case_item case_item_list
|
||||||
|
case_item = CASE argument_list STATEMENT_TERMINATOR job_list
|
||||||
|
|
||||||
|
argument_list_nonempty = <TOK_STRING> argument_list
|
||||||
|
argument_list = <empty> | argument_list_nonempty
|
||||||
|
|
||||||
block_statement = block_header STATEMENT_TERMINATOR job_list <END> arguments_or_redirections_list
|
block_statement = block_header STATEMENT_TERMINATOR job_list <END> arguments_or_redirections_list
|
||||||
block_header = for_header | while_header | function_header | begin_header
|
block_header = for_header | while_header | function_header | begin_header
|
||||||
for_header = FOR var_name IN arguments_or_redirections_list
|
for_header = FOR var_name IN arguments_or_redirections_list
|
||||||
while_header = WHILE statement
|
while_header = WHILE statement
|
||||||
begin_header = BEGIN
|
begin_header = BEGIN
|
||||||
function_header = FUNCTION function_name arguments_or_redirections_list
|
function_header = FUNCTION function_name argument_list
|
||||||
|
|
||||||
|
|
||||||
#(TODO: functions should not support taking redirections in their arguments)
|
|
||||||
|
|
||||||
# A boolean statement is AND or OR or NOT
|
# A boolean statement is AND or OR or NOT
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue