diff options
Diffstat (limited to 'parser.h')
-rw-r--r-- | parser.h | 291 |
1 files changed, 89 insertions, 202 deletions
@@ -11,11 +11,9 @@ #include "util.h" #include "event.h" #include "function.h" +#include "parse_tree.h" #include <vector> -#define PARSER_TEST_ERROR 1 -#define PARSER_TEST_INCOMPLETE 2 - /** event_blockage_t represents a block on events of the specified type */ @@ -66,8 +64,15 @@ enum block_type_t SOURCE, /**< Block created by the . (source) builtin */ EVENT, /**< Block created on event notifier invocation */ BREAKPOINT, /**< Breakpoint block */ -} -; +}; + +/** Possible states for a loop */ +enum loop_status_t +{ + LOOP_NORMAL, /**< Current loop block executed as normal */ + LOOP_BREAK, /**< Current loop block should be removed */ + LOOP_CONTINUE, /**< Current loop block should be skipped */ +}; /** block_t represents a block of commands. @@ -80,55 +85,31 @@ protected: private: const block_type_t block_type; /**< Type of block. */ - bool made_fake; public: block_type_t type() const { - return this->made_fake ? FAKE : this->block_type; + return this->block_type; } - /** Mark a block as fake; this is used by the return statement. */ - void mark_as_fake() - { - this->made_fake = true; - } + /** Description of the block, for debugging */ + wcstring description() const; bool skip; /**< Whether execution of the commands in this block should be skipped */ - bool had_command; /**< Set to non-zero once a command has been executed in this block */ int tok_pos; /**< The start index of the block */ - /** - Status for the current loop block. Can be any of the values from the loop_status enum. - */ - int loop_status; + node_offset_t node_offset; /* Offset of the node */ - /** - The job that is currently evaluated in the specified block. - */ - job_t *job; + /** Status for the current loop block. Can be any of the values from the loop_status enum. */ + enum loop_status_t loop_status; -#if 0 - union - { - int while_state; /**< True if the loop condition has not yet been evaluated*/ - wchar_t *for_variable; /**< Name of the variable to loop over */ - int if_state; /**< The state of the if block, can be one of IF_STATE_UNTESTED, IF_STATE_FALSE, IF_STATE_TRUE */ - wchar_t *switch_value; /**< The value to test in a switch block */ - const wchar_t *source_dest; /**< The name of the file to source*/ - event_t *event; /**<The event that triggered this block */ - wchar_t *function_call_name; - } param1; -#endif + /** The job that is currently evaluated in the specified block. */ + job_t *job; - /** - Name of file that created this block - */ + /** Name of file that created this block. This string is intern'd. */ const wchar_t *src_filename; - /** - Line number where this block was created - */ + /** Line number where this block was created */ int src_lineno; /** Whether we should pop the environment variable stack when we're popped off of the block stack */ @@ -137,22 +118,12 @@ public: /** List of event blocks. */ event_blockage_list_t event_blocks; - /** - Next outer block - */ - block_t *outer; - /** Destructor */ virtual ~block_t(); }; struct if_block_t : public block_t { - bool if_expr_evaluated; // whether we've evaluated the if expression - bool is_elseif_entry; // whether we're at the beginning of an ELSEIF branch - bool any_branch_taken; // whether the clause of the if statement or any elseif has been found to be true - bool else_evaluated; // whether we've encountered a terminal else block - if_block_t(); }; @@ -177,22 +148,17 @@ struct source_block_t : public block_t struct for_block_t : public block_t { - wcstring variable; // the variable that will be assigned each value in the sequence - wcstring_list_t sequence; // the sequence of values - for_block_t(const wcstring &var); + for_block_t(); }; struct while_block_t : public block_t { - int status; while_block_t(); }; struct switch_block_t : public block_t { - bool switch_taken; - const wcstring switch_value; - switch_block_t(const wcstring &sv); + switch_block_t(); }; struct fake_block_t : public block_t @@ -200,12 +166,6 @@ struct fake_block_t : public block_t fake_block_t(); }; -struct function_def_block_t : public block_t -{ - function_data_t function_data; - function_def_block_t(); -}; - struct scope_block_t : public block_t { scope_block_t(block_type_t type); //must be BEGIN, TOP or SUBST @@ -217,29 +177,6 @@ struct breakpoint_block_t : public block_t }; /** - Possible states for a loop -*/ -enum loop_status -{ - LOOP_NORMAL, /**< Current loop block executed as normal */ - LOOP_BREAK, /**< Current loop block should be removed */ - LOOP_CONTINUE, /**< Current loop block should be skipped */ -}; - - -/** - Possible states for a while block -*/ -enum while_status -{ - WHILE_TEST_FIRST, /**< This is the first command of the first lap of a while loop */ - WHILE_TEST_AGAIN, /**< This is not the first lap of the while loop, but it is the first command of the loop */ - WHILE_TESTED, /**< This is not the first command in the loop */ -} -; - - -/** Errors that can be generated by the parser */ enum parser_error @@ -273,90 +210,64 @@ enum parser_type_t struct profile_item_t { - /** - Time spent executing the specified command, including parse time for nested blocks. - */ + /** Time spent executing the specified command, including parse time for nested blocks. */ int exec; - /** - Time spent parsing the specified command, including execution time for command substitutions. - */ + + /** Time spent parsing the specified command, including execution time for command substitutions. */ int parse; - /** - The block level of the specified command. nested blocks and command substitutions both increase the block level. - */ + + /** The block level of the specified command. nested blocks and command substitutions both increase the block level. */ size_t level; - /** - If the execution of this command was skipped. - */ - int skipped; - /** - The command string. - */ + + /** If the execution of this command was skipped. */ + bool skipped; + + /** The command string. */ wcstring cmd; }; struct tokenizer_t; +class parse_execution_context_t; class parser_t { + friend class parse_execution_context_t; private: enum parser_type_t parser_type; - std::vector<block_t> blocks; /** Whether or not we output errors */ const bool show_errors; - /** Last error code */ - int error_code; - - /** Position of last error */ - int err_pos; - - /** Description of last error */ - wcstring err_buff; - - /** Pointer to the current tokenizer */ - tokenizer_t *current_tokenizer; + /** Indication that we should skip all blocks */ + bool cancellation_requested; - /** String for representing the current line */ - wcstring lineinfo; + /** Indicates that we are within the process of initializing fish */ + bool is_within_fish_initialization; - /** This is the position of the beginning of the currently parsed command */ - int current_tokenizer_pos; + /** Stack of execution contexts. We own these pointers and must delete them */ + std::vector<parse_execution_context_t *> execution_contexts; /** List of called functions, used to help prevent infinite recursion */ wcstring_list_t forbidden_function; - /** String index where the current job started. */ - int job_start_pos; - /** The jobs associated with this parser */ job_list_t my_job_list; - /** - Keeps track of how many recursive eval calls have been made. Eval - doesn't call itself directly, recursion happens on blocks and on - command substitutions. - */ - int eval_level; + /** The list of blocks, allocated with new. It's our responsibility to delete these */ + std::vector<block_t *> block_stack; + + /** Gets a description of the block stack, for debugging */ + wcstring block_stack_description() const; + + /** List of profile items, allocated with new */ + std::vector<profile_item_t *> profile_items; /* No copying allowed */ parser_t(const parser_t&); parser_t& operator=(const parser_t&); - void parse_job_argument_list(process_t *p, job_t *j, tokenizer_t *tok, std::vector<completion_t>&, bool); - int parse_job(process_t *p, job_t *j, tokenizer_t *tok); - void skipped_exec(job_t * j); - void eval_job(tokenizer_t *tok); - int parser_test_argument(const wchar_t *arg, wcstring *out, const wchar_t *prefix, int offset); - void print_errors(wcstring &target, const wchar_t *prefix); - void print_errors_stderr(); - - /** Create a job */ - job_t *job_create(); - -public: - std::vector<profile_item_t*> profile_items; + /** Adds a job to the beginning of the job list. */ + void job_add(job_t *job); /** Returns the name of the currently evaluated function if we are @@ -366,6 +277,8 @@ public: */ const wchar_t *is_function() const; +public: + /** Get the "principal" parser, whatever that is */ static parser_t &principal_parser(); @@ -377,15 +290,9 @@ public: /** Create a parser of the given type */ parser_t(enum parser_type_t type, bool show_errors); - /** The current innermost block, allocated with new */ - block_t *current_block; - /** Global event blocks */ event_blockage_list_t global_event_blocks; - /** Current block level io redirections */ - io_chain_t block_io; - /** Evaluate the expressions contained in cmd. @@ -395,29 +302,20 @@ public: \return 0 on success, 1 otherwise */ - int eval(const wcstring &cmdStr, const io_chain_t &io, enum block_type_t block_type); + int eval(const wcstring &cmd, const io_chain_t &io, enum block_type_t block_type); - /** - Evaluate line as a list of parameters, i.e. tokenize it and perform parameter expansion and cmdsubst execution on the tokens. - The output is inserted into output, and should be freed by the caller. - - \param line Line to evaluate - \param output List to insert output to - */ - /** - \param line Line to evaluate - \param output List to insert output to - */ - int eval_args(const wchar_t *line, std::vector<completion_t> &output); + /** Evaluates a block node at the given node offset in the topmost execution context */ + int eval_block_node(node_offset_t node_idx, const io_chain_t &io, enum block_type_t block_type); /** - Sets the current evaluation error. This function should only be used by libraries that are called by + Evaluate line as a list of parameters, i.e. tokenize it and perform parameter expansion and cmdsubst execution on the tokens. + The output is inserted into output. + Errors are ignored. - \param ec The new error code - \param p The character offset at which the error occured - \param str The printf-style error message filter + \param arg_src String to evaluate as an argument list + \param output List to insert output into */ - void error(int ec, int p, const wchar_t *str, ...); + void expand_argument_list(const wcstring &arg_src, std::vector<completion_t> &output); /** Returns a string describing the current parser pisition in the format 'FILENAME (line LINE_NUMBER): LINE'. @@ -425,25 +323,24 @@ public: init.fish (line 127): ls|grep pancake */ - const wchar_t *current_line(); + wcstring current_line(); /** Returns the current line number */ int get_lineno() const; - /** Returns the line number for the character at the given index */ - int line_number_of_character_at_offset(size_t idx) const; - - /** Returns the current position in the latest string of the tokenizer. */ - int get_pos() const; - - /** Returns the position where the current job started in the latest string of the tokenizer. */ - int get_job_pos() const; + /** Returns the block at the given index. 0 corresponds to the innermost block. Returns NULL when idx is at or equal to the number of blocks. */ + const block_t *block_at_index(size_t idx) const; + block_t *block_at_index(size_t idx); - /** Set the current position in the latest string of the tokenizer. */ - void set_pos(int p); + /** Returns the current (innermost) block */ + const block_t *current_block() const; + block_t *current_block(); - /** Get the string currently parsed */ - const wchar_t *get_buffer() const; + /** Count of blocks */ + size_t block_count() const + { + return block_stack.size(); + } /** Get the list of jobs */ job_list_t &job_list() @@ -451,12 +348,18 @@ public: return my_job_list; } + /* Hackish. In order to correctly report the origin of code with no associated file, we need to know whether it's run during initialization or not. */ + void set_is_within_fish_initialization(bool flag); + /** Pushes the block. pop_block will call delete on it. */ void push_block(block_t *newv); /** Remove the outermost block namespace */ void pop_block(); + /** Remove the outermost block, asserting it's the given one */ + void pop_block(const block_t *b); + /** Return a description of the given blocktype */ const wchar_t *get_block_desc(int block) const; @@ -472,6 +375,9 @@ public: /** Returns the job with the given pid */ job_t *job_get_from_pid(int pid); + /* Returns a new profile item if profiling is active. The caller should fill it in. The parser_t will clean it up. */ + profile_item_t *create_profile_item(); + /** Test if the specified string can be parsed, or if more bytes need to be read first. The result will have the PARSER_TEST_ERROR bit @@ -484,15 +390,12 @@ public: \param out if non-null, any errors in the command will be filled out into this buffer \param prefix the prefix string to prepend to each error message written to the \c out buffer */ - int test(const wchar_t * buff, int *block_level = NULL, wcstring *out = NULL, const wchar_t *prefix = NULL); + void get_backtrace(const wcstring &src, const parse_error_list_t &errors, wcstring *output) const; /** - Test if the specified string can be parsed as an argument list, - e.g. sent to eval_args. The result has the first bit set if the - string contains errors, and the second bit is set if the string - contains an unclosed block. + Detect errors in the specified string when parsed as an argument list. Returns true if an error occurred. */ - int test_args(const wchar_t * buff, wcstring *out, const wchar_t *prefix); + bool detect_errors_in_argument_list(const wcstring &arg_list_src, wcstring *out_err, const wchar_t *prefix); /** Tell the parser that the specified function may not be run if not @@ -500,28 +403,16 @@ public: of infinite recursion. */ void forbid_function(const wcstring &function); + /** Undo last call to parser_forbid_function(). */ void allow_function(); /** - Initialize static parser data - */ - void init(); - - /** - Destroy static parser data + Output profiling data to the given filename */ - void destroy(); - - /** - This function checks if the specified string is a help option. - - \param s the string to test - \param min_match is the minimum number of characters that must match in a long style option, i.e. the longest common prefix between --help and any other option. If less than 3, 3 will be assumed. - */ - int is_help(const wchar_t *s, int min_match) const; + void emit_profiling(const char *path) const; /** Returns the file currently evaluated by the parser. This can be @@ -533,11 +424,7 @@ public: /** Write a stack trace starting at the specified block to the specified wcstring */ - void stack_trace(block_t *b, wcstring &buff); - - int get_block_type(const wchar_t *cmd) const; - const wchar_t *get_block_command(int type) const; + void stack_trace(size_t block_idx, wcstring &buff) const; }; - #endif |