mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-26 12:53:13 +00:00
If statements parse
This commit is contained in:
parent
66af0c1a53
commit
eba5b0e4c5
3 changed files with 130 additions and 49 deletions
|
@ -229,29 +229,6 @@ class parse_exec_t
|
|||
pop();
|
||||
}
|
||||
|
||||
void assemble_if_header(exec_node_t &exec_node, const parse_node_t &header)
|
||||
{
|
||||
PARSE_ASSERT(header.type == symbol_if_header);
|
||||
PARSE_ASSERT(&header == &parse_tree.at(exec_node.parse_node_idx));
|
||||
PARSE_ASSERT(exec_node.body_parse_node_idx != NODE_OFFSET_INVALID);
|
||||
if_header_t if_header;
|
||||
if_header.body = exec_node.body_parse_node_idx;
|
||||
// We may hit this on enter or exit
|
||||
if (! exec_node.visited)
|
||||
{
|
||||
// Entry. Don't pop the header - just push the job. We'll pop it on exit.
|
||||
exec_node.visited = true;
|
||||
visitor->enter_if_header(if_header);
|
||||
push(header.child_offset(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Exit. Pop it.
|
||||
visitor->exit_if_header(if_header);
|
||||
pop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void enter_parse_node(size_t idx);
|
||||
void run_top_node(void);
|
||||
|
@ -367,11 +344,11 @@ void parse_exec_t::run_top_node()
|
|||
break;
|
||||
}
|
||||
|
||||
case symbol_if_header:
|
||||
case symbol_if_statement:
|
||||
{
|
||||
PARSE_ASSERT(parse_node.child_count == 2);
|
||||
assemble_if_header(exec_node, parse_node);
|
||||
break;
|
||||
PARSE_ASSERT(parse_node.child_count == 3);
|
||||
|
||||
|
||||
}
|
||||
|
||||
case symbol_decorated_statement:
|
||||
|
|
124
parse_tree.cpp
124
parse_tree.cpp
|
@ -51,11 +51,16 @@ wcstring token_type_description(parse_token_type_t type)
|
|||
case symbol_statement: return L"statement";
|
||||
case symbol_block_statement: return L"block_statement";
|
||||
case symbol_block_header: return L"block_header";
|
||||
case symbol_if_header: return L"if_header";
|
||||
case symbol_for_header: return L"for_header";
|
||||
case symbol_while_header: return L"while_header";
|
||||
case symbol_begin_header: return L"begin_header";
|
||||
case symbol_function_header: return L"function_header";
|
||||
|
||||
case symbol_if_statement: return L"if_statement";
|
||||
case symbol_if_clause: return L"if_clause";
|
||||
case symbol_else_clause: return L"else_clause";
|
||||
case symbol_else_continuation: return L"else_continuation";
|
||||
|
||||
case symbol_boolean_statement: return L"boolean_statement";
|
||||
case symbol_decorated_statement: return L"decorated_statement";
|
||||
case symbol_plain_statement: return L"plain_statement";
|
||||
|
@ -213,6 +218,17 @@ struct parse_stack_element_t
|
|||
parse_stack_element_t(parse_keyword_t k) : type(parse_token_type_string), keyword(k), node_idx(-1)
|
||||
{
|
||||
}
|
||||
|
||||
wcstring describe(void) const
|
||||
{
|
||||
wcstring result = token_type_description(type);
|
||||
if (keyword != parse_keyword_none)
|
||||
{
|
||||
append_format(result, L" <%ls>", keyword_description(keyword).c_str());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class parse_ll_t
|
||||
|
@ -244,7 +260,8 @@ class parse_ll_t
|
|||
void accept_token_job_continuation(parse_token_t token);
|
||||
void accept_token_statement(parse_token_t token);
|
||||
void accept_token_block_header(parse_token_t token);
|
||||
void accept_token_if_header(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_boolean_statement(parse_token_t token);
|
||||
void accept_token_decorated_statement(parse_token_t token);
|
||||
void accept_token_plain_statement(parse_token_t token);
|
||||
|
@ -257,6 +274,8 @@ class parse_ll_t
|
|||
void parse_error(const wchar_t *expected, parse_token_t token);
|
||||
void append_error_callout(wcstring &error_message, parse_token_t token);
|
||||
|
||||
void dump_stack(void) const;
|
||||
|
||||
// Get the node corresponding to the top element of the stack
|
||||
parse_node_t &node_for_top_symbol()
|
||||
{
|
||||
|
@ -294,11 +313,11 @@ class parse_ll_t
|
|||
if (1)
|
||||
{
|
||||
fprintf(stderr, "Pop %ls\n", token_type_description(symbol_stack.back().type).c_str());
|
||||
if (tok5.type != token_type_invalid) fprintf(stderr, "Push %ls\n", token_type_description(tok5.type).c_str());
|
||||
if (tok4.type != token_type_invalid) fprintf(stderr, "Push %ls\n", token_type_description(tok4.type).c_str());
|
||||
if (tok3.type != token_type_invalid) fprintf(stderr, "Push %ls\n", token_type_description(tok3.type).c_str());
|
||||
if (tok2.type != token_type_invalid) fprintf(stderr, "Push %ls\n", token_type_description(tok2.type).c_str());
|
||||
if (tok1.type != token_type_invalid) fprintf(stderr, "Push %ls\n", token_type_description(tok1.type).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 (tok3.type != token_type_invalid) fprintf(stderr, "Push %ls\n", tok3.describe().c_str());
|
||||
if (tok2.type != token_type_invalid) fprintf(stderr, "Push %ls\n", tok2.describe().c_str());
|
||||
if (tok1.type != token_type_invalid) fprintf(stderr, "Push %ls\n", tok1.describe().c_str());
|
||||
}
|
||||
|
||||
// Get the node for the top symbol and tell it about its children
|
||||
|
@ -329,9 +348,41 @@ class parse_ll_t
|
|||
}
|
||||
};
|
||||
|
||||
void parse_ll_t::dump_stack(void) const
|
||||
{
|
||||
// Walk backwards from the top, looking for parents
|
||||
wcstring_list_t lines;
|
||||
if (symbol_stack.empty())
|
||||
{
|
||||
lines.push_back(L"(empty)");
|
||||
}
|
||||
else
|
||||
{
|
||||
node_offset_t child = symbol_stack.back().node_idx;
|
||||
node_offset_t cursor = child;
|
||||
lines.push_back(nodes.at(cursor).describe());
|
||||
while (cursor--)
|
||||
{
|
||||
const parse_node_t &node = nodes.at(cursor);
|
||||
if (node.child_start <= child && node.child_start + node.child_count > child)
|
||||
{
|
||||
lines.push_back(node.describe());
|
||||
child = cursor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "Stack dump (%lu elements):\n", symbol_stack.size());
|
||||
for (size_t idx = 0; idx < lines.size(); idx++)
|
||||
{
|
||||
fprintf(stderr, " %ls\n", lines.at(idx).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void parse_ll_t::token_unhandled(parse_token_t token, const char *function)
|
||||
{
|
||||
fprintf(stderr, "Unhandled token with type %ls in function %s\n", token_type_description(token.type).c_str(), function);
|
||||
this->dump_stack();
|
||||
PARSER_DIE();
|
||||
}
|
||||
|
||||
|
@ -424,7 +475,6 @@ void parse_ll_t::accept_token_statement(parse_token_t token)
|
|||
symbol_stack_pop_push(symbol_boolean_statement);
|
||||
break;
|
||||
|
||||
case parse_keyword_if:
|
||||
case parse_keyword_for:
|
||||
case parse_keyword_while:
|
||||
case parse_keyword_function:
|
||||
|
@ -432,6 +482,10 @@ void parse_ll_t::accept_token_statement(parse_token_t token)
|
|||
symbol_stack_pop_push(symbol_block_statement);
|
||||
break;
|
||||
|
||||
case parse_keyword_if:
|
||||
symbol_stack_pop_push(symbol_if_statement);
|
||||
break;
|
||||
|
||||
case parse_keyword_else:
|
||||
case parse_keyword_switch:
|
||||
symbol_stack_pop_push(symbol_block_statement);
|
||||
|
@ -475,10 +529,6 @@ void parse_ll_t::accept_token_block_header(parse_token_t token)
|
|||
case parse_token_type_string:
|
||||
switch (token.keyword)
|
||||
{
|
||||
case parse_keyword_if:
|
||||
symbol_stack_pop_push(symbol_if_header);
|
||||
break;
|
||||
|
||||
case parse_keyword_else:
|
||||
PARSER_DIE(); //todo
|
||||
break;
|
||||
|
@ -513,6 +563,36 @@ void parse_ll_t::accept_token_block_header(parse_token_t token)
|
|||
}
|
||||
}
|
||||
|
||||
void parse_ll_t::accept_token_else_clause(parse_token_t token)
|
||||
{
|
||||
PARSE_ASSERT(stack_top_type() == symbol_else_clause);
|
||||
switch (token.keyword)
|
||||
{
|
||||
case parse_keyword_else:
|
||||
symbol_stack_pop_push(parse_keyword_else, symbol_else_continuation);
|
||||
break;
|
||||
|
||||
default:
|
||||
symbol_stack_pop_push();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void parse_ll_t::accept_token_else_continuation(parse_token_t token)
|
||||
{
|
||||
PARSE_ASSERT(stack_top_type() == symbol_else_continuation);
|
||||
switch (token.keyword)
|
||||
{
|
||||
case parse_keyword_if:
|
||||
symbol_stack_pop_push(symbol_if_clause, symbol_else_clause);
|
||||
break;
|
||||
|
||||
default:
|
||||
symbol_stack_pop_push(parse_token_type_end, symbol_job_list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void parse_ll_t::accept_token_boolean_statement(parse_token_t token)
|
||||
{
|
||||
PARSE_ASSERT(stack_top_type() == symbol_boolean_statement);
|
||||
|
@ -705,6 +785,22 @@ void parse_ll_t::accept_token(parse_token_t token, const wcstring &src)
|
|||
accept_token_statement(token);
|
||||
break;
|
||||
|
||||
case symbol_if_statement:
|
||||
symbol_stack_pop_push(symbol_if_clause, symbol_else_clause, parse_keyword_end);
|
||||
break;
|
||||
|
||||
case symbol_if_clause:
|
||||
symbol_stack_pop_push(parse_keyword_if, symbol_job, parse_token_type_end, symbol_job_list);
|
||||
break;
|
||||
|
||||
case symbol_else_clause:
|
||||
accept_token_else_clause(token);
|
||||
break;
|
||||
|
||||
case symbol_else_continuation:
|
||||
accept_token_else_continuation(token);
|
||||
break;
|
||||
|
||||
case symbol_block_statement:
|
||||
symbol_stack_pop_push(symbol_block_header, parse_token_type_end, symbol_job_list, parse_keyword_end, symbol_arguments_or_redirections_list);
|
||||
break;
|
||||
|
@ -713,10 +809,6 @@ void parse_ll_t::accept_token(parse_token_t token, const wcstring &src)
|
|||
accept_token_block_header(token);
|
||||
break;
|
||||
|
||||
case symbol_if_header:
|
||||
symbol_stack_pop_push(parse_keyword_if, symbol_job);
|
||||
break;
|
||||
|
||||
case symbol_for_header:
|
||||
symbol_stack_pop_push(parse_keyword_for, parse_token_type_string, parse_keyword_in, symbol_arguments_or_redirections_list, parse_token_type_end);
|
||||
break;
|
||||
|
|
22
parse_tree.h
22
parse_tree.h
|
@ -15,7 +15,7 @@
|
|||
#include <vector>
|
||||
|
||||
#define PARSE_ASSERT(a) assert(a)
|
||||
#define PARSER_DIE() assert(0)
|
||||
#define PARSER_DIE() exit_without_destructors(-1)
|
||||
|
||||
class parse_node_t;
|
||||
class parse_node_tree_t;
|
||||
|
@ -58,11 +58,16 @@ enum parse_token_type_t
|
|||
symbol_statement,
|
||||
symbol_block_statement,
|
||||
symbol_block_header,
|
||||
symbol_if_header,
|
||||
symbol_for_header,
|
||||
symbol_while_header,
|
||||
symbol_begin_header,
|
||||
symbol_function_header,
|
||||
|
||||
symbol_if_statement,
|
||||
symbol_if_clause,
|
||||
symbol_else_clause,
|
||||
symbol_else_continuation,
|
||||
|
||||
symbol_boolean_statement,
|
||||
symbol_decorated_statement,
|
||||
symbol_plain_statement,
|
||||
|
@ -159,18 +164,25 @@ class parse_node_tree_t : public std::vector<parse_node_t>
|
|||
|
||||
# A statement is a normal command, or an if / while / and etc
|
||||
|
||||
statement = boolean_statement | block_statement | decorated_statement
|
||||
statement = boolean_statement | block_statement | if_statement | decorated_statement
|
||||
|
||||
# A block is a conditional, loop, or begin/end
|
||||
|
||||
if_statement = if_clause else_clause <END>
|
||||
if_clause = <IF> job STATEMENT_TERMINATOR job_list
|
||||
else_clause = <empty> |
|
||||
<ELSE> else_continuation
|
||||
else_continuation = if_clause else_clause |
|
||||
STATEMENT_TERMINATOR job_list
|
||||
|
||||
block_statement = block_header STATEMENT_TERMINATOR job_list <END> arguments_or_redirections_list
|
||||
block_header = if_header | for_header | while_header | function_header | begin_header
|
||||
if_header = IF job
|
||||
block_header = for_header | while_header | function_header | begin_header
|
||||
for_header = FOR var_name IN arguments_or_redirections_list
|
||||
while_header = WHILE statement
|
||||
begin_header = BEGIN
|
||||
function_header = FUNCTION function_name arguments_or_redirections_list
|
||||
|
||||
|
||||
#(TODO: functions should not support taking redirections in their arguments)
|
||||
|
||||
# A boolean statement is AND or OR or NOT
|
||||
|
|
Loading…
Reference in a new issue