2005-09-20 23:26:39 +10:00
/** \file parser.h
2011-12-26 19:18:46 -08:00
The fish parser .
2005-09-20 23:26:39 +10:00
*/
2005-10-05 01:11:39 +10:00
# ifndef FISH_PARSER_H
# define FISH_PARSER_H
# include <wchar.h>
# include "proc.h"
# include "util.h"
2006-02-02 01:49:11 +10:00
# include "event.h"
2012-02-07 22:10:35 -08:00
# include "function.h"
2012-01-16 11:09:19 -08:00
# include <vector>
2005-10-05 01:11:39 +10:00
2006-10-02 02:02:58 +10:00
# define PARSER_TEST_ERROR 1
# define PARSER_TEST_INCOMPLETE 2
2006-01-24 06:40:14 +10:00
/**
2012-08-26 22:42:29 -07:00
event_blockage_t represents a block on events of the specified type
2006-01-24 06:40:14 +10:00
*/
2012-08-26 22:42:29 -07:00
struct event_blockage_t
2005-12-12 08:21:01 +10:00
{
/**
The types of events to block . This is interpreted as a bitset
whete the value is 1 for every bit corresponding to a blocked
event type . For example , if EVENT_VARIABLE type events should
2011-12-26 19:18:46 -08:00
be blocked , ( type & 1 < < EVENT_BLOCKED ) should be set .
2005-12-12 08:21:01 +10:00
Note that EVENT_ANY can be used to specify any event .
*/
2012-02-07 21:04:51 -08:00
unsigned int typemask ;
} ;
2012-08-26 22:42:29 -07:00
typedef std : : list < event_blockage_t > event_blockage_list_t ;
2012-02-07 21:04:51 -08:00
2012-08-26 22:42:29 -07:00
inline bool event_block_list_blocks_type ( const event_blockage_list_t & ebls , int type ) {
for ( event_blockage_list_t : : const_iterator iter = ebls . begin ( ) ; iter ! = ebls . end ( ) ; + + iter ) {
2012-02-07 21:04:51 -08:00
if ( iter - > typemask & ( 1 < < EVENT_ANY ) )
return true ;
if ( iter - > typemask & ( 1 < < type ) )
return true ;
}
return false ;
}
2005-12-12 08:21:01 +10:00
2012-08-26 22:42:29 -07:00
/**
Types of blocks
*/
enum block_type_t
{
WHILE , /**< While loop block */
FOR , /**< For loop block */
IF , /**< If block */
FUNCTION_DEF , /**< Function definition block */
FUNCTION_CALL , /**< Function invocation block */
FUNCTION_CALL_NO_SHADOW , /**< Function invocation block with no variable shadowing */
SWITCH , /**< Switch block */
FAKE , /**< Fake block */
SUBST , /**< Command substitution scope */
TOP , /**< Outermost block */
BEGIN , /**< Unconditional block */
SOURCE , /**< Block created by the . (source) builtin */
EVENT , /**< Block created on event notifier invocation */
BREAKPOINT , /**< Breakpoint block */
}
;
2005-09-20 23:26:39 +10:00
/**
2011-12-26 19:18:46 -08:00
block_t represents a block of commands .
2005-09-20 23:26:39 +10:00
*/
2012-08-26 22:42:29 -07:00
struct block_t
2005-09-20 23:26:39 +10:00
{
2012-08-26 23:16:20 -07:00
protected :
/** Protected constructor. Use one of the subclasses below. */
block_t ( block_type_t t ) ;
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 ; }
/** Mark a block as fake; this is used by the return statement. */
void mark_as_fake ( ) { this - > made_fake = true ; }
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 */
2005-09-20 23:26:39 +10:00
int tok_pos ; /**< The start index of the block */
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
/**
2005-12-12 08:21:01 +10:00
Status for the current loop block . Can be any of the values from the loop_status enum .
2005-09-20 23:26:39 +10:00
*/
int loop_status ;
2005-10-15 10:51:26 +10:00
/**
2005-12-12 08:21:01 +10:00
The job that is currently evaluated in the specified block .
2005-10-15 10:51:26 +10:00
*/
job_t * job ;
2011-12-26 19:18:46 -08:00
2012-02-07 17:06:45 -08:00
#if 0
2011-12-26 19:18:46 -08:00
union
2005-09-20 23:26:39 +10:00
{
int while_state ; /**< True if the loop condition has not yet been evaluated*/
wchar_t * for_variable ; /**< Name of the variable to loop over */
2006-09-09 00:12:41 +10:00
int if_state ; /**< The state of the if block, can be one of IF_STATE_UNTESTED, IF_STATE_FALSE, IF_STATE_TRUE */
2005-09-20 23:26:39 +10:00
wchar_t * switch_value ; /**< The value to test in a switch block */
2006-02-03 01:23:56 +10:00
const wchar_t * source_dest ; /**< The name of the file to source*/
2012-02-13 11:42:58 -08:00
event_t * event ; /**<The event that triggered this block */
2006-09-09 00:12:41 +10:00
wchar_t * function_call_name ;
2005-10-12 05:31:16 +10:00
} param1 ;
2012-02-07 17:06:45 -08:00
# endif
2005-09-20 23:26:39 +10:00
2006-02-02 01:49:11 +10:00
/**
Name of file that created this block
*/
2006-02-03 01:23:56 +10:00
const wchar_t * src_filename ;
2011-12-26 19:18:46 -08:00
2006-02-02 01:49:11 +10:00
/**
Line number where this block was created
*/
int src_lineno ;
2012-02-07 17:06:45 -08:00
2012-02-07 21:04:51 -08:00
/** Whether we should pop the environment variable stack when we're popped off of the block stack */
2012-02-07 17:06:45 -08:00
bool wants_pop_env ;
2011-12-26 19:18:46 -08:00
2012-02-07 21:04:51 -08:00
/** List of event blocks. */
2012-08-26 22:42:29 -07:00
event_blockage_list_t event_blocks ;
2011-12-26 19:18:46 -08:00
2005-09-20 23:26:39 +10:00
/**
2011-12-26 19:18:46 -08:00
Next outer block
2005-09-20 23:26:39 +10:00
*/
2012-08-26 22:42:29 -07:00
block_t * outer ;
2012-08-26 23:16:20 -07:00
2012-02-07 17:06:45 -08:00
/** Destructor */
2012-08-26 22:42:29 -07:00
virtual ~ block_t ( ) ;
} ;
2012-08-26 23:34:34 -07:00
struct if_block_t : public block_t
{
2012-08-26 22:42:29 -07:00
bool if_expr_evaluated ; // whether the clause of the if statement has been tested
bool if_expr_result ; // if so, whether it evaluated to true
bool else_evaluated ; // whether we've encountered a terminal else block
2012-08-26 23:16:20 -07:00
if_block_t ( ) ;
2012-08-26 22:42:29 -07:00
} ;
2005-09-20 23:26:39 +10:00
2012-08-26 23:34:34 -07:00
struct event_block_t : public block_t
{
2012-08-26 22:42:29 -07:00
const event_t * const event ;
2012-08-26 23:16:20 -07:00
event_block_t ( const event_t * evt ) ;
2012-08-26 22:42:29 -07:00
} ;
2012-08-26 23:34:34 -07:00
struct function_block_t : public block_t
{
2012-08-26 22:42:29 -07:00
process_t * process ;
wcstring name ;
2012-08-26 23:16:20 -07:00
function_block_t ( process_t * p , const wcstring & n , bool shadows ) ;
2012-08-26 22:42:29 -07:00
} ;
2012-08-26 23:34:34 -07:00
struct source_block_t : public block_t
{
2012-08-26 22:42:29 -07:00
const wchar_t * const source_file ;
2012-08-26 23:16:20 -07:00
source_block_t ( const wchar_t * src ) ;
2012-08-26 22:42:29 -07:00
} ;
2012-08-26 23:34:34 -07:00
struct for_block_t : public block_t
{
2012-08-26 22:42:29 -07:00
wcstring variable ; // the variable that will be assigned each value in the sequence
wcstring_list_t sequence ; // the sequence of values
2012-08-26 23:16:20 -07:00
for_block_t ( const wcstring & var ) ;
2012-08-26 22:42:29 -07:00
} ;
2012-08-26 23:34:34 -07:00
struct while_block_t : public block_t
{
2012-08-26 22:42:29 -07:00
int status ;
2012-08-26 23:16:20 -07:00
while_block_t ( ) ;
2012-08-26 22:42:29 -07:00
} ;
2012-08-26 23:34:34 -07:00
struct switch_block_t : public block_t
{
2012-08-26 22:42:29 -07:00
bool switch_taken ;
const wcstring switch_value ;
2012-08-26 23:16:20 -07:00
switch_block_t ( const wcstring & sv ) ;
} ;
2012-08-26 23:34:34 -07:00
struct fake_block_t : public block_t
{
2012-08-26 23:16:20 -07:00
fake_block_t ( ) ;
} ;
2012-08-26 23:34:34 -07:00
struct function_def_block_t : public block_t
{
2012-08-26 23:30:23 -07:00
function_data_t function_data ;
2012-08-26 23:16:20 -07:00
function_def_block_t ( ) ;
} ;
2012-08-26 23:34:34 -07:00
struct scope_block_t : public block_t
{
2012-08-26 23:16:20 -07:00
scope_block_t ( block_type_t type ) ; //must be BEGIN, TOP or SUBST
} ;
2012-08-26 23:34:34 -07:00
struct breakpoint_block_t : public block_t
{
2012-08-26 23:16:20 -07:00
breakpoint_block_t ( ) ;
2012-08-26 22:42:29 -07:00
} ;
2005-09-20 23:26:39 +10:00
/**
Possible states for a loop
*/
2011-12-26 19:18:46 -08:00
enum loop_status
2005-09-20 23:26:39 +10:00
{
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
*/
2011-12-26 19:18:46 -08:00
enum parser_error
2005-09-20 23:26:39 +10:00
{
2005-12-04 02:43:56 +10:00
/**
No error
*/
2005-09-20 23:26:39 +10:00
NO_ERR = 0 ,
2005-12-04 02:43:56 +10:00
/**
2011-12-26 19:18:46 -08:00
An error in the syntax
2005-12-04 02:43:56 +10:00
*/
2005-09-20 23:26:39 +10:00
SYNTAX_ERROR ,
2005-12-04 02:43:56 +10:00
/**
Error occured while evaluating commands
*/
2005-09-20 23:26:39 +10:00
EVAL_ERROR ,
2005-12-04 02:43:56 +10:00
/**
2006-08-23 00:38:31 +10:00
Error while evaluating cmdsubst
2005-12-04 02:43:56 +10:00
*/
2006-08-23 00:38:31 +10:00
CMDSUBST_ERROR ,
2012-01-16 11:09:19 -08:00
} ;
2005-09-20 23:26:39 +10:00
2012-01-16 12:10:08 -08:00
enum parser_type_t {
PARSER_TYPE_NONE ,
PARSER_TYPE_GENERAL ,
PARSER_TYPE_FUNCTIONS_ONLY ,
2012-01-30 23:58:30 +05:30
PARSER_TYPE_COMPLETIONS_ONLY ,
PARSER_TYPE_ERRORS_ONLY
2012-01-16 12:10:08 -08:00
} ;
2012-01-20 11:24:43 -08:00
struct profile_item_t {
/**
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 .
*/
int parse ;
/**
The block level of the specified command . nested blocks and command substitutions both increase the block level .
*/
2012-01-22 20:47:13 -08:00
size_t level ;
2012-01-20 11:24:43 -08:00
/**
If the execution of this command was skipped .
*/
int skipped ;
/**
The command string .
*/
wcstring cmd ;
} ;
2012-01-19 10:28:44 -08:00
2012-01-22 20:47:13 -08:00
struct tokenizer ;
2012-01-16 11:09:19 -08:00
class parser_t {
private :
2012-01-22 21:40:08 -08:00
enum parser_type_t parser_type ;
2012-01-16 11:09:19 -08:00
std : : vector < block_t > blocks ;
2012-05-06 13:36:51 -07:00
/** Whether or not we output errors */
const bool show_errors ;
2012-01-22 21:57:30 -08:00
/** Last error code */
int error_code ;
2012-05-06 13:36:51 -07:00
2012-01-22 21:57:30 -08:00
/** Position of last error */
int err_pos ;
/** Description of last error */
2012-02-09 18:43:36 -08:00
wcstring err_buff ;
2012-01-22 21:57:30 -08:00
/** Pointer to the current tokenizer */
tokenizer * current_tokenizer ;
/** String for representing the current line */
2012-02-22 10:51:06 -08:00
wcstring lineinfo ;
2012-01-22 21:57:30 -08:00
/** This is the position of the beginning of the currently parsed command */
int current_tokenizer_pos ;
/** List of called functions, used to help prevent infinite recursion */
2012-01-29 22:06:58 -08:00
wcstring_list_t forbidden_function ;
2012-01-22 21:57:30 -08:00
/** String index where the current job started. */
int job_start_pos ;
2012-02-27 18:43:24 -08:00
/** The jobs associated with this parser */
job_list_t my_job_list ;
2012-01-22 21:57:30 -08:00
/**
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 ;
2012-01-16 12:10:08 -08:00
/* No copying allowed */
parser_t ( const parser_t & ) ;
parser_t & operator = ( const parser_t & ) ;
2012-01-29 14:11:39 +05:30
void parse_job_argument_list ( process_t * p , job_t * j , tokenizer * tok , std : : vector < completion_t > & ) ;
2012-01-22 20:47:13 -08:00
int parse_job ( process_t * p , job_t * j , tokenizer * tok ) ;
void skipped_exec ( job_t * j ) ;
void eval_job ( tokenizer * tok ) ;
2012-02-22 10:51:06 -08:00
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 ) ;
2012-01-22 21:57:30 -08:00
void print_errors_stderr ( ) ;
2012-01-22 20:47:13 -08:00
2012-01-16 11:09:19 -08:00
public :
2012-01-19 10:28:44 -08:00
std : : vector < profile_item_t > profile_items ;
2012-01-16 11:16:12 -08:00
2012-04-21 20:08:08 -07:00
/**
Returns the name of the currently evaluated function if we are
currently evaluating a function , null otherwise . This is tested by
moving down the block - scope - stack , checking every block if it is of
type FUNCTION_CALL .
*/
const wchar_t * is_function ( ) const ;
2012-01-22 21:40:08 -08:00
/** Get the "principal" parser, whatever that is */
static parser_t & principal_parser ( ) ;
2012-06-04 14:20:01 -07:00
/** Indicates that execution of all blocks in the principal parser should stop.
This is called from signal handlers !
*/
static void skip_all_blocks ( ) ;
2012-01-16 12:10:08 -08:00
/** Create a parser of the given type */
2012-05-06 13:36:51 -07:00
parser_t ( enum parser_type_t type , bool show_errors ) ;
2012-01-16 12:10:08 -08:00
2012-02-07 17:06:45 -08:00
/** The current innermost block, allocated with new */
2012-01-16 12:10:08 -08:00
block_t * current_block ;
2012-01-16 11:09:19 -08:00
/** Global event blocks */
2012-08-26 22:42:29 -07:00
event_blockage_list_t global_event_blocks ;
2012-01-16 11:09:19 -08:00
/** Current block level io redirections */
2012-08-15 00:57:56 -07:00
io_chain_t block_io ;
2012-01-16 11:09:19 -08:00
/**
Evaluate the expressions contained in cmd .
2005-12-08 02:06:47 +10:00
2012-01-16 11:09:19 -08:00
\ param cmd the string to evaluate
\ param io io redirections to perform on all started jobs
\ param block_type The type of block to push on the block stack
2005-09-20 23:26:39 +10:00
2012-01-16 11:09:19 -08:00
\ return 0 on success , 1 otherwise
*/
2012-08-15 00:57:56 -07:00
int eval ( const wcstring & cmdStr , const io_chain_t & io , enum block_type_t block_type ) ;
2012-01-16 11:09:19 -08:00
/**
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
*/
2012-01-29 14:11:39 +05:30
/**
\ param line Line to evaluate
\ param output List to insert output to
*/
int eval_args ( const wchar_t * line , std : : vector < completion_t > & output ) ;
2005-09-20 23:26:39 +10:00
2012-01-16 11:09:19 -08:00
/**
Sets the current evaluation error . This function should only be used by libraries that are called by
\ param ec The new error code
\ param p The character offset at which the error occured
\ param str The printf - style error message filter
*/
void error ( int ec , int p , const wchar_t * str , . . . ) ;
/**
Returns a string describing the current parser pisition in the format ' FILENAME ( line LINE_NUMBER ) : LINE ' .
Example :
2005-09-20 23:26:39 +10:00
2012-01-16 11:09:19 -08:00
init . fish ( line 127 ) : ls | grep pancake
*/
2012-01-22 20:47:13 -08:00
const wchar_t * current_line ( ) ;
2005-09-20 23:26:39 +10:00
2012-02-27 18:43:24 -08:00
/** Returns the current line number */
2012-01-16 11:16:12 -08:00
int get_lineno ( ) const ;
2012-08-04 17:44:14 -07:00
/** Returns the line number for the character at the given index */
int line_number_of_character_at_offset ( size_t idx ) const ;
2006-01-27 00:48:10 +10:00
2012-02-27 18:43:24 -08:00
/** Returns the current position in the latest string of the tokenizer. */
2012-01-16 11:16:12 -08:00
int get_pos ( ) const ;
2005-09-20 23:26:39 +10:00
2012-02-27 18:43:24 -08:00
/** Returns the position where the current job started in the latest string of the tokenizer. */
2012-01-16 11:16:12 -08:00
int get_job_pos ( ) const ;
2005-09-20 23:26:39 +10:00
2012-02-27 18:43:24 -08:00
/** Set the current position in the latest string of the tokenizer. */
2012-01-22 21:40:08 -08:00
void set_pos ( int p ) ;
2005-09-20 23:26:39 +10:00
2012-02-27 18:43:24 -08:00
/** Get the string currently parsed */
2012-01-16 11:16:12 -08:00
const wchar_t * get_buffer ( ) const ;
2012-02-27 18:43:24 -08:00
/** Get the list of jobs */
job_list_t & job_list ( ) { return my_job_list ; }
2005-09-20 23:26:39 +10:00
2012-08-26 22:42:29 -07:00
/** Pushes the block. pop_block will call delete on it. */
void push_block ( block_t * newv ) ;
2005-09-20 23:26:39 +10:00
2012-02-27 18:43:24 -08:00
/** Remove the outermost block namespace */
2012-01-16 11:09:19 -08:00
void pop_block ( ) ;
2005-09-20 23:26:39 +10:00
2012-02-27 18:43:24 -08:00
/** Return a description of the given blocktype */
2012-01-16 11:16:12 -08:00
const wchar_t * get_block_desc ( int block ) const ;
2005-09-20 23:26:39 +10:00
2012-02-27 18:43:24 -08:00
/** Create a job */
job_t * job_create ( ) ;
/** Removes a job */
bool job_remove ( job_t * job ) ;
/** Promotes a job to the front of the list */
void job_promote ( job_t * job ) ;
/** Return the job with the specified job id. If id is 0 or less, return the last job used. */
job_t * job_get ( int job_id ) ;
/** Returns the job with the given pid */
job_t * job_get_from_pid ( int pid ) ;
2005-09-20 23:26:39 +10:00
2012-01-16 11:09:19 -08:00
/**
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
set if there is a syntax error in the code , and the
PARSER_TEST_INCOMPLETE bit set if the code contains unclosed
blocks .
\ param buff the text buffer to test
\ param block_level if non - null , the block nesting level will be filled out into this array
\ 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
*/
2012-02-22 10:51:06 -08:00
int test ( const wchar_t * buff , int * block_level , wcstring * out , const wchar_t * prefix ) ;
2006-05-22 05:25:24 +10:00
2012-01-16 11:09:19 -08:00
/**
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 .
*/
2012-02-22 10:51:06 -08:00
int test_args ( const wchar_t * buff , wcstring * out , const wchar_t * prefix ) ;
2005-09-20 23:26:39 +10:00
2012-01-16 11:09:19 -08:00
/**
Tell the parser that the specified function may not be run if not
inside of a conditional block . This is to remove some possibilities
of infinite recursion .
*/
2012-01-29 22:06:58 -08:00
void forbid_function ( const wcstring & function ) ;
2012-01-16 11:09:19 -08:00
/**
Undo last call to parser_forbid_function ( ) .
*/
void allow_function ( ) ;
2005-09-20 23:26:39 +10:00
2012-01-16 11:09:19 -08:00
/**
Initialize static parser data
*/
void init ( ) ;
2005-09-20 23:26:39 +10:00
2012-01-16 11:09:19 -08:00
/**
Destroy static parser data
*/
void destroy ( ) ;
2005-09-20 23:26:39 +10:00
2012-01-16 11:09:19 -08:00
/**
This function checks if the specified string is a help option .
2005-09-20 23:26:39 +10:00
2012-01-16 11:09:19 -08:00
\ 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 .
*/
2012-01-29 22:06:58 -08:00
int is_help ( const wchar_t * s , int min_match ) const ;
2005-09-20 23:26:39 +10:00
2012-01-16 11:09:19 -08:00
/**
Returns the file currently evaluated by the parser . This can be
different than reader_current_filename , e . g . if we are evaulating a
function defined in a different file than the one curently read .
*/
2012-01-16 11:16:12 -08:00
const wchar_t * current_filename ( ) const ;
2006-01-27 01:47:22 +10:00
2012-01-16 11:09:19 -08:00
/**
2012-02-22 10:51:06 -08:00
Write a stack trace starting at the specified block to the specified wcstring
2012-01-16 11:09:19 -08:00
*/
2012-02-22 10:51:06 -08:00
void stack_trace ( block_t * b , wcstring & buff ) ;
2006-01-31 03:54:26 +10:00
2012-01-16 11:16:12 -08:00
int get_block_type ( const wchar_t * cmd ) const ;
const wchar_t * get_block_command ( int type ) const ;
} ;
2006-09-06 06:43:47 +10:00
2006-01-27 01:47:22 +10:00
2005-10-05 01:11:39 +10:00
# endif