mirror of
https://github.com/fish-shell/fish-shell
synced 2024-11-11 23:47:25 +00:00
c31ad3ed07
Fixes #1136
338 lines
10 KiB
C++
338 lines
10 KiB
C++
/**\file parse_constants.h
|
|
|
|
Constants used in the programmatic representation of fish code.
|
|
*/
|
|
|
|
#ifndef fish_parse_constants_h
|
|
#define fish_parse_constants_h
|
|
|
|
#include "config.h"
|
|
|
|
#define PARSE_ASSERT(a) assert(a)
|
|
#define PARSER_DIE() do { fprintf(stderr, "Parser dying!\n"); exit_without_destructors(-1); } while (0)
|
|
|
|
enum parse_token_type_t
|
|
{
|
|
token_type_invalid,
|
|
|
|
// Non-terminal tokens
|
|
symbol_job_list,
|
|
symbol_job,
|
|
symbol_job_continuation,
|
|
symbol_statement,
|
|
symbol_block_statement,
|
|
symbol_block_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_switch_statement,
|
|
symbol_case_item_list,
|
|
symbol_case_item,
|
|
|
|
symbol_boolean_statement,
|
|
symbol_decorated_statement,
|
|
symbol_plain_statement,
|
|
symbol_arguments_or_redirections_list,
|
|
symbol_argument_or_redirection,
|
|
|
|
symbol_argument_list,
|
|
|
|
// "freestanding" argument lists are parsed from the argument list supplied to 'complete -a'
|
|
// They are not generated by parse trees rooted in symbol_job_list
|
|
symbol_freestanding_argument_list,
|
|
|
|
symbol_argument,
|
|
symbol_redirection,
|
|
|
|
symbol_optional_background,
|
|
|
|
symbol_end_command,
|
|
|
|
// Terminal types
|
|
parse_token_type_string,
|
|
parse_token_type_pipe,
|
|
parse_token_type_redirection,
|
|
parse_token_type_background,
|
|
parse_token_type_end,
|
|
|
|
// Special terminal type that means no more tokens forthcoming
|
|
parse_token_type_terminate,
|
|
|
|
// Very special terminal types that don't appear in the production list
|
|
parse_special_type_parse_error,
|
|
parse_special_type_tokenizer_error,
|
|
parse_special_type_comment,
|
|
|
|
FIRST_TERMINAL_TYPE = parse_token_type_string,
|
|
LAST_TERMINAL_TYPE = parse_token_type_terminate,
|
|
|
|
LAST_TOKEN_OR_SYMBOL = parse_token_type_terminate,
|
|
FIRST_PARSE_TOKEN_TYPE = parse_token_type_string
|
|
} __packed;
|
|
|
|
/* These must be maintained in sorted order (except for none, which isn't a keyword). This enables us to do binary search. */
|
|
enum parse_keyword_t
|
|
{
|
|
parse_keyword_none,
|
|
parse_keyword_and,
|
|
parse_keyword_begin,
|
|
parse_keyword_builtin,
|
|
parse_keyword_case,
|
|
parse_keyword_command,
|
|
parse_keyword_else,
|
|
parse_keyword_end,
|
|
parse_keyword_exec,
|
|
parse_keyword_for,
|
|
parse_keyword_function,
|
|
parse_keyword_if,
|
|
parse_keyword_in,
|
|
parse_keyword_not,
|
|
parse_keyword_or,
|
|
parse_keyword_switch,
|
|
parse_keyword_while,
|
|
LAST_KEYWORD = parse_keyword_while
|
|
} __packed;
|
|
|
|
/* Statement decorations. This matches the order of productions in decorated_statement */
|
|
enum parse_statement_decoration_t
|
|
{
|
|
parse_statement_decoration_none,
|
|
parse_statement_decoration_command,
|
|
parse_statement_decoration_builtin,
|
|
parse_statement_decoration_exec
|
|
};
|
|
|
|
/* Boolean statement types */
|
|
enum parse_bool_statement_type_t
|
|
{
|
|
parse_bool_and,
|
|
parse_bool_or,
|
|
parse_bool_not
|
|
};
|
|
|
|
/* Parse error code list */
|
|
enum parse_error_code_t
|
|
{
|
|
parse_error_none,
|
|
|
|
/* Matching values from enum parser_error */
|
|
parse_error_syntax,
|
|
parse_error_eval,
|
|
parse_error_cmdsubst,
|
|
|
|
parse_error_generic, // unclassified error types
|
|
|
|
//tokenizer errors
|
|
parse_error_tokenizer_unterminated_quote,
|
|
parse_error_tokenizer_unterminated_subshell,
|
|
parse_error_tokenizer_unterminated_escape,
|
|
parse_error_tokenizer_other,
|
|
|
|
parse_error_unbalancing_end, //end outside of block
|
|
parse_error_unbalancing_else, //else outside of if
|
|
parse_error_unbalancing_case, //case outside of switch
|
|
|
|
parse_error_double_pipe, // foo || bar, has special error message
|
|
parse_error_double_background // foo && bar, has special error message
|
|
};
|
|
|
|
enum
|
|
{
|
|
PARSER_TEST_ERROR = 1,
|
|
PARSER_TEST_INCOMPLETE = 2
|
|
};
|
|
typedef unsigned int parser_test_error_bits_t;
|
|
|
|
struct parse_error_t
|
|
{
|
|
/** Text of the error */
|
|
wcstring text;
|
|
|
|
/** Code for the error */
|
|
enum parse_error_code_t code;
|
|
|
|
/** 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. If skip_caret is false, the offending line with a caret is printed as well */
|
|
wcstring describe(const wcstring &src) const;
|
|
|
|
/** Return a string describing the error, suitable for presentation to the user, with the given prefix. If skip_caret is false, the offending line with a caret is printed as well */
|
|
wcstring describe_with_prefix(const wcstring &src, const wcstring &prefix, bool is_interactive, bool skip_caret) const;
|
|
};
|
|
typedef std::vector<parse_error_t> parse_error_list_t;
|
|
|
|
/* Special source_start value that means unknown */
|
|
#define SOURCE_LOCATION_UNKNOWN (static_cast<size_t>(-1))
|
|
|
|
/* Helper function to offset error positions by the given amount. This is used when determining errors in a substring of a larger source buffer. */
|
|
void parse_error_offset_source_start(parse_error_list_t *errors, size_t amt);
|
|
|
|
/** Maximum number of function calls. */
|
|
#define FISH_MAX_STACK_DEPTH 128
|
|
|
|
/** Error message on a function that calls itself immediately */
|
|
#define INFINITE_FUNC_RECURSION_ERR_MSG _( L"The function '%ls' calls itself immediately, which would result in an infinite loop.")
|
|
|
|
|
|
/** Error message on reaching maximum call stack depth */
|
|
#define CALL_STACK_LIMIT_EXCEEDED_ERR_MSG _( L"The function call stack limit has been exceeded. Do you have an accidental infinite loop?")
|
|
|
|
/** Error message when a non-string token is found when expecting a command name */
|
|
#define CMD_OR_ERR_MSG _( L"Expected a command, but instead found a pipe. Did you mean 'COMMAND; or COMMAND'? See the help section for the 'or' builtin command by typing 'help or'.")
|
|
|
|
/** Error message when a non-string token is found when expecting a command name */
|
|
#define CMD_AND_ERR_MSG _( L"Expected a command, but instead found a '&'. Did you mean 'COMMAND; and COMMAND'? See the help section for the 'and' builtin command by typing 'help and'.")
|
|
|
|
/** Error message when encountering an illegal command name */
|
|
#define ILLEGAL_CMD_ERR_MSG _( L"Illegal command name '%ls'")
|
|
|
|
/** Error message when encountering an unknown builtin name */
|
|
#define UNKNOWN_BUILTIN_ERR_MSG _( L"Unknown builtin '%ls'")
|
|
|
|
/** Error message when encountering a failed expansion, e.g. for the variable name in for loops */
|
|
#define FAILED_EXPANSION_VARIABLE_NAME_ERR_MSG _( L"Unable to expand variable name '%ls'")
|
|
|
|
/** Error message when encountering a failed process expansion, e.g. %notaprocess */
|
|
#define FAILED_EXPANSION_PROCESS_ERR_MSG _( L"Unable to find a process '%ls'")
|
|
|
|
/** Error message when encountering an illegal file descriptor */
|
|
#define ILLEGAL_FD_ERR_MSG _( L"Illegal file descriptor in redirection '%ls'")
|
|
|
|
/** Error message for wildcards with no matches */
|
|
#define WILDCARD_ERR_MSG _( L"No matches for wildcard '%ls'.")
|
|
|
|
/** Error when using break outside of loop */
|
|
#define INVALID_BREAK_ERR_MSG _( L"break command while not inside of loop" )
|
|
|
|
/** Error when using continue outside of loop */
|
|
#define INVALID_CONTINUE_ERR_MSG _( L"continue command while not inside of loop" )
|
|
|
|
/** Error when using return builtin outside of function definition */
|
|
#define INVALID_RETURN_ERR_MSG _( L"'return' builtin command outside of function definition" )
|
|
|
|
/** Error message for Posix-style assignment: foo=bar */
|
|
#define COMMAND_ASSIGN_ERR_MSG _( L"Unknown command '%ls'. Did you mean 'set %ls %ls'? See the help section on the set command by typing 'help set'.")
|
|
|
|
/**
|
|
Error issued on invalid variable name
|
|
*/
|
|
#define COMPLETE_VAR_DESC _( L"The '$' character begins a variable name. The character '%lc', which directly followed a '$', is not allowed as a part of a variable name, and variable names may not be zero characters long. To learn more about variable expansion in fish, type 'help expand-variable'.")
|
|
|
|
/**
|
|
Error issued on $?
|
|
*/
|
|
#define COMPLETE_YOU_WANT_STATUS _( L"$? is not a valid variable in fish. If you want the exit status of the last command, try $status.")
|
|
|
|
/**
|
|
Error issued on invalid variable name
|
|
*/
|
|
#define COMPLETE_VAR_NULL_DESC _( L"The '$' begins a variable name. It was given at the end of an argument. Variable names may not be zero characters long. To learn more about variable expansion in fish, type 'help expand-variable'.")
|
|
|
|
/**
|
|
Error issued on invalid variable name
|
|
*/
|
|
#define COMPLETE_VAR_BRACKET_DESC _( L"Did you mean %ls{$%ls}%ls? The '$' character begins a variable name. A bracket, which directly followed a '$', is not allowed as a part of a variable name, and variable names may not be zero characters long. To learn more about variable expansion in fish, type 'help expand-variable'." )
|
|
|
|
/**
|
|
Error issued on invalid variable name
|
|
*/
|
|
#define COMPLETE_VAR_PARAN_DESC _( L"Did you mean (COMMAND)? In fish, the '$' character is only used for accessing variables. To learn more about command substitution in fish, type 'help expand-command-substitution'.")
|
|
|
|
/**
|
|
While block description
|
|
*/
|
|
#define WHILE_BLOCK N_( L"'while' block" )
|
|
|
|
/**
|
|
For block description
|
|
*/
|
|
#define FOR_BLOCK N_( L"'for' block" )
|
|
|
|
/**
|
|
Breakpoint block
|
|
*/
|
|
#define BREAKPOINT_BLOCK N_( L"Block created by breakpoint" )
|
|
|
|
|
|
|
|
/**
|
|
If block description
|
|
*/
|
|
#define IF_BLOCK N_( L"'if' conditional block" )
|
|
|
|
|
|
/**
|
|
Function definition block description
|
|
*/
|
|
#define FUNCTION_DEF_BLOCK N_( L"function definition block" )
|
|
|
|
|
|
/**
|
|
Function invocation block description
|
|
*/
|
|
#define FUNCTION_CALL_BLOCK N_( L"function invocation block" )
|
|
|
|
/**
|
|
Function invocation block description
|
|
*/
|
|
#define FUNCTION_CALL_NO_SHADOW_BLOCK N_( L"function invocation block with no variable shadowing" )
|
|
|
|
|
|
/**
|
|
Switch block description
|
|
*/
|
|
#define SWITCH_BLOCK N_( L"'switch' block" )
|
|
|
|
|
|
/**
|
|
Fake block description
|
|
*/
|
|
#define FAKE_BLOCK N_( L"unexecutable block" )
|
|
|
|
|
|
/**
|
|
Top block description
|
|
*/
|
|
#define TOP_BLOCK N_( L"global root block" )
|
|
|
|
|
|
/**
|
|
Command substitution block description
|
|
*/
|
|
#define SUBST_BLOCK N_( L"command substitution block" )
|
|
|
|
|
|
/**
|
|
Begin block description
|
|
*/
|
|
#define BEGIN_BLOCK N_( L"'begin' unconditional block" )
|
|
|
|
|
|
/**
|
|
Source block description
|
|
*/
|
|
#define SOURCE_BLOCK N_( L"Block created by the . builtin" )
|
|
|
|
/**
|
|
Source block description
|
|
*/
|
|
#define EVENT_BLOCK N_( L"event handler block" )
|
|
|
|
|
|
/**
|
|
Unknown block description
|
|
*/
|
|
#define UNKNOWN_BLOCK N_( L"unknown/invalid block" )
|
|
|
|
|
|
|
|
#endif
|