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"
# include "parser.h"
2006-02-02 01:49:11 +10:00
# include "event.h"
2012-01-16 11:09:19 -08:00
# include <vector>
2012-02-07 21:04:51 -08:00
# include <deque>
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
/**
event_block_t represents a block on events of the specified type
*/
2012-02-07 21:04:51 -08:00
struct event_block_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 ;
} ;
typedef std : : deque < event_block_t > event_block_list_t ;
inline bool event_block_list_blocks_type ( const event_block_list_t & ebls , int type ) {
for ( event_block_list_t : : const_iterator iter = ebls . begin ( ) ; iter ! = ebls . end ( ) ; iter + + ) {
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-02-07 17:06:45 -08:00
/** Block state template, to replace the discriminated union */
struct block_state_base_t {
public :
virtual ~ block_state_base_t ( ) { }
} ;
template < typename T >
struct block_state_t : public block_state_base_t {
T value ;
block_state_t ( ) : value ( ) { }
} ;
2005-12-12 08:21:01 +10:00
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
*/
typedef struct block
{
int type ; /**< Type of block. Can be one of WHILE, FOR, IF and FUNCTION */
int skip ; /**< Whether execution of the commands in this block should be skipped */
int tok_pos ; /**< The start index of the block */
2006-11-02 23:45:37 +10:00
int had_command ; /**< Set to non-zero once a command has been executed in this 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 ;
2006-09-09 00:12:41 +10:00
/**
Block type - specific data
*/
void * data ;
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*/
2011-12-26 19:18:46 -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
2012-02-07 17:06:45 -08:00
/** First block type specific variable */
block_state_base_t * state1_ptr ;
template < typename T >
T & state1 ( void ) {
block_state_t < T > * state ;
if ( state1_ptr = = NULL ) {
state = new block_state_t < T > ( ) ;
state1_ptr = state ;
} else {
state = dynamic_cast < block_state_t < T > * > ( state1_ptr ) ;
assert ( state ! = NULL ) ;
}
return state - > value ;
}
/** Second block type specific variable */
block_state_base_t * state2_ptr ;
template < typename T >
T & state2 ( void ) {
block_state_t < T > * state ;
if ( state2_ptr = = NULL ) {
state = new block_state_t < T > ( ) ;
state2_ptr = state ;
} else {
state = dynamic_cast < block_state_t < T > * > ( state2_ptr ) ;
assert ( state ! = NULL ) ;
}
return state - > value ;
}
#if 0
2005-09-20 23:26:39 +10:00
/**
Second block type specific variable
*/
union
{
2011-12-26 19:18:46 -08:00
array_list_t for_vars ; /**< List of values for a for block */
2005-09-20 23:26:39 +10:00
int switch_taken ; /**< Whether a switch match has already been found */
2006-02-02 01:49:11 +10:00
process_t * function_call_process ; /**< The process representing this function call */
2005-10-12 05:31:16 +10:00
} param2 ;
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. */
event_block_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-02-07 17:06:45 -08:00
struct block * outer ;
/** Destructor */
~ block ( )
{
if ( state1_ptr ! = NULL )
delete state1_ptr ;
if ( state2_ptr ! = NULL )
delete state2_ptr ;
}
2005-09-20 23:26:39 +10:00
} block_t ;
2011-12-26 19:18:46 -08:00
/**
2005-09-20 23:26:39 +10:00
Types of blocks
*/
2012-01-16 11:09:19 -08:00
enum block_type_t
2005-09-20 23:26:39 +10:00
{
WHILE , /**< While loop block */
FOR , /**< For loop block */
IF , /**< If block */
FUNCTION_DEF , /**< Function definition block */
FUNCTION_CALL , /**< Function invocation block */
2007-04-23 08:10:33 +10:00
FUNCTION_CALL_NO_SHADOW , /**< Function invocation block with no variable shadowing */
2005-09-20 23:26:39 +10:00
SWITCH , /**< Switch block */
FAKE , /**< Fake block */
SUBST , /**< Command substitution scope */
TOP , /**< Outermost block */
BEGIN , /**< Unconditional block */
2006-01-28 21:34:40 +10:00
SOURCE , /**< Block created by the . (source) builtin */
2006-02-02 01:49:11 +10:00
EVENT , /**< Block created on event notifier invocation */
2006-11-11 20:54:00 +10:00
BREAKPOINT , /**< Breakpoint block */
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-01-22 21:57:30 -08:00
/** Last error code */
int error_code ;
/** Position of last error */
int err_pos ;
/** Description of last error */
string_buffer_t * err_buff ;
/** Pointer to the current tokenizer */
tokenizer * current_tokenizer ;
/** String for representing the current line */
string_buffer_t * lineinfo ;
/** 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 ;
/**
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-22 21:57:30 -08: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-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 ) ;
int parser_test_argument ( const wchar_t * arg , string_buffer_t * out , const wchar_t * prefix , int offset ) ;
void print_errors ( string_buffer_t * 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-01-22 21:40:08 -08:00
/** Get the "principal" parser, whatever that is */
static parser_t & principal_parser ( ) ;
2012-01-16 12:10:08 -08:00
/** Create a parser of the given type */
parser_t ( enum parser_type_t type ) ;
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-02-07 21:04:51 -08:00
event_block_list_t global_event_blocks ;
2012-01-16 11:09:19 -08:00
/** Current block level io redirections */
2012-01-22 20:47:13 -08:00
io_data_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
*/
int eval ( const wcstring & cmd , io_data_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
*/
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-01-16 11:09:19 -08:00
/**
Returns the current line number
*/
2012-01-16 11:16:12 -08:00
int get_lineno ( ) const ;
2006-01-27 00:48:10 +10:00
2012-01-16 11:09:19 -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-01-16 11:09:19 -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-01-16 11:09:19 -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-01-16 11:09:19 -08:00
/**
Get the string currently parsed
*/
2012-01-16 11:16:12 -08:00
const wchar_t * get_buffer ( ) const ;
2005-09-20 23:26:39 +10:00
2012-01-16 11:09:19 -08:00
/**
Create block of specified type
*/
void push_block ( int type ) ;
2005-09-20 23:26:39 +10:00
2012-01-16 11:09:19 -08:00
/**
Remove the outermost block namespace
*/
void pop_block ( ) ;
2005-09-20 23:26:39 +10:00
2012-01-16 11:09:19 -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-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-01-22 21:40:08 -08:00
int test ( const wchar_t * buff , int * block_level , string_buffer_t * 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-01-22 21:40:08 -08:00
int test_args ( const wchar_t * buff , string_buffer_t * 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
/**
Write a stack trace starting at the specified block to the specified string_buffer_t
*/
void stack_trace ( block_t * b , string_buffer_t * 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