aboutsummaryrefslogtreecommitdiffhomepage
path: root/parser.h
diff options
context:
space:
mode:
Diffstat (limited to 'parser.h')
-rw-r--r--parser.h291
1 files changed, 89 insertions, 202 deletions
diff --git a/parser.h b/parser.h
index fa49fcfb..4c03bd96 100644
--- a/parser.h
+++ b/parser.h
@@ -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