2013-06-10 05:21:24 +08:00
|
|
|
/**\file parse_tree.h
|
2013-05-27 03:12:16 +08:00
|
|
|
|
|
|
|
Programmatic representation of fish code.
|
|
|
|
*/
|
|
|
|
|
2013-06-10 05:21:24 +08:00
|
|
|
#ifndef FISH_PARSE_TREE_H
|
|
|
|
#define FISH_PARSE_TREE_H
|
2013-05-27 03:12:16 +08:00
|
|
|
|
|
|
|
#include <wchar.h>
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "common.h"
|
2013-06-02 13:14:47 +08:00
|
|
|
#include "tokenizer.h"
|
2013-06-12 00:37:51 +08:00
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#define PARSE_ASSERT(a) assert(a)
|
|
|
|
#define PARSER_DIE() assert(0)
|
2013-05-27 03:12:16 +08:00
|
|
|
|
2013-06-16 05:32:38 +08:00
|
|
|
class parse_node_t;
|
|
|
|
typedef std::vector<parse_node_t> parse_node_tree_t;
|
|
|
|
typedef size_t node_offset_t;
|
|
|
|
|
2013-06-16 06:21:35 +08:00
|
|
|
struct parse_error_t
|
|
|
|
{
|
|
|
|
/** Text of the error */
|
|
|
|
wcstring text;
|
|
|
|
|
|
|
|
/** Offset and length of the token in the source code that triggered this error */
|
|
|
|
size_t source_start;
|
|
|
|
size_t source_length;
|
|
|
|
|
|
|
|
/** Return a string describing the error, suitable for presentation to the user */
|
|
|
|
wcstring describe(const wcstring &src) const;
|
|
|
|
};
|
|
|
|
typedef std::vector<parse_error_t> parse_error_list_t;
|
2013-05-27 03:12:16 +08:00
|
|
|
|
2013-06-02 13:14:47 +08:00
|
|
|
class parse_ll_t;
|
|
|
|
class parse_t
|
|
|
|
{
|
2013-06-07 12:49:40 +08:00
|
|
|
parse_ll_t * const parser;
|
2013-06-09 10:20:26 +08:00
|
|
|
|
|
|
|
public:
|
2013-06-02 13:14:47 +08:00
|
|
|
parse_t();
|
2013-06-16 06:21:35 +08:00
|
|
|
bool parse(const wcstring &str, parse_node_tree_t *output, parse_error_list_t *errors);
|
2013-06-02 13:14:47 +08:00
|
|
|
};
|
|
|
|
|
2013-06-12 00:37:51 +08:00
|
|
|
|
|
|
|
enum parse_token_type_t
|
|
|
|
{
|
|
|
|
token_type_invalid,
|
|
|
|
|
|
|
|
// Non-terminal tokens
|
|
|
|
symbol_statement_list,
|
|
|
|
symbol_statement,
|
|
|
|
symbol_block_statement,
|
|
|
|
symbol_block_header,
|
|
|
|
symbol_if_header,
|
|
|
|
symbol_for_header,
|
|
|
|
symbol_while_header,
|
|
|
|
symbol_begin_header,
|
|
|
|
symbol_function_header,
|
|
|
|
symbol_boolean_statement,
|
|
|
|
symbol_decorated_statement,
|
|
|
|
symbol_plain_statement,
|
|
|
|
symbol_arguments_or_redirections_list,
|
|
|
|
symbol_argument_or_redirection,
|
|
|
|
|
|
|
|
// Terminal types
|
|
|
|
parse_token_type_string,
|
|
|
|
parse_token_type_pipe,
|
|
|
|
parse_token_type_redirection,
|
|
|
|
parse_token_background,
|
|
|
|
parse_token_type_end,
|
|
|
|
parse_token_type_terminate,
|
|
|
|
|
|
|
|
FIRST_PARSE_TOKEN_TYPE = parse_token_type_string
|
|
|
|
};
|
|
|
|
|
|
|
|
enum parse_keyword_t
|
|
|
|
{
|
|
|
|
parse_keyword_none,
|
|
|
|
parse_keyword_if,
|
|
|
|
parse_keyword_else,
|
|
|
|
parse_keyword_for,
|
|
|
|
parse_keyword_in,
|
|
|
|
parse_keyword_while,
|
|
|
|
parse_keyword_begin,
|
|
|
|
parse_keyword_function,
|
|
|
|
parse_keyword_switch,
|
|
|
|
parse_keyword_end,
|
|
|
|
parse_keyword_and,
|
|
|
|
parse_keyword_or,
|
|
|
|
parse_keyword_not,
|
|
|
|
parse_keyword_command,
|
|
|
|
parse_keyword_builtin
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Base class for nodes of a parse tree */
|
|
|
|
class parse_node_t
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
/* Type of the node */
|
|
|
|
enum parse_token_type_t type;
|
|
|
|
|
|
|
|
/* Start in the source code */
|
|
|
|
size_t source_start;
|
|
|
|
|
|
|
|
/* Length of our range in the source code */
|
|
|
|
size_t source_length;
|
|
|
|
|
|
|
|
/* Children */
|
|
|
|
node_offset_t child_start;
|
|
|
|
node_offset_t child_count;
|
|
|
|
|
|
|
|
/* Type-dependent data */
|
|
|
|
uint32_t tag;
|
|
|
|
|
|
|
|
|
|
|
|
/* Description */
|
|
|
|
wcstring describe(void) const;
|
|
|
|
|
|
|
|
/* Constructor */
|
|
|
|
explicit parse_node_t(parse_token_type_t ty) : type(ty), source_start(0), source_length(0), child_start(0), child_count(0), tag(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-06-09 10:20:26 +08:00
|
|
|
|
|
|
|
|
2013-05-27 03:12:16 +08:00
|
|
|
/* Fish grammar:
|
|
|
|
|
|
|
|
# A statement_list is a list of statements, separated by semicolons or newlines
|
|
|
|
|
2013-06-02 13:14:47 +08:00
|
|
|
statement_list = <empty> |
|
|
|
|
statement statement_list
|
2013-05-27 03:12:16 +08:00
|
|
|
|
2013-06-19 14:35:04 +08:00
|
|
|
# A statement is a normal job, or an if / while / and etc, or just a nothing (i.e. newline)
|
2013-05-27 03:12:16 +08:00
|
|
|
|
2013-06-19 14:35:04 +08:00
|
|
|
statement = boolean_statement | block_statement | decorated_statement | <TOK_END>
|
2013-05-27 03:12:16 +08:00
|
|
|
|
|
|
|
# A block is a conditional, loop, or begin/end
|
|
|
|
|
|
|
|
block_statement = block_header statement_list END arguments_or_redirections_list
|
|
|
|
block_header = if_header | for_header | while_header | function_header | begin_header
|
|
|
|
if_header = IF statement
|
|
|
|
for_header = FOR var_name IN arguments_or_redirections_list STATEMENT_TERMINATOR
|
|
|
|
while_header = WHILE statement
|
|
|
|
begin_header = BEGIN STATEMENT_TERMINATOR
|
|
|
|
function_header = FUNCTION arguments_or_redirections_list STATEMENT_TERMINATOR
|
|
|
|
|
|
|
|
# A boolean statement is AND or OR or NOT
|
|
|
|
|
|
|
|
boolean_statement = AND statement | OR statement | NOT statement
|
|
|
|
|
|
|
|
# A decorated_statement is a command with a list of arguments_or_redirections, possibly with "builtin" or "command"
|
|
|
|
|
|
|
|
decorated_statement = COMMAND plain_statement | BUILTIN plain_statement | plain_statement
|
|
|
|
plain_statement = command arguments_or_redirections_list terminator
|
|
|
|
|
2013-06-02 13:14:47 +08:00
|
|
|
arguments_or_redirections_list = <empty> |
|
|
|
|
argument_or_redirection arguments_or_redirections_list
|
|
|
|
argument_or_redirection = redirection | <TOK_STRING>
|
|
|
|
redirection = <TOK_REDIRECTION>
|
|
|
|
|
|
|
|
terminator = <TOK_END> | <TOK_BACKGROUND>
|
2013-05-27 03:12:16 +08:00
|
|
|
|
2013-06-02 13:14:47 +08:00
|
|
|
*/
|
2013-05-27 03:12:16 +08:00
|
|
|
|
|
|
|
#endif
|