Make the validator show the help for a block command missing an 'end'

darcs-hash:20060616125616-ac50b-b895cc14ce9f26ec99ac90523b2a52d0dce66dd9.gz
This commit is contained in:
axel 2006-06-16 22:56:16 +10:00
parent d2869d5140
commit 907b2f8462

219
parser.c
View file

@ -177,78 +177,78 @@ The fish parser. Contains functions for parsing code.
/** /**
While block description While block description
*/ */
#define WHILE_BLOCK _( L"'while' block" ) #define WHILE_BLOCK N_( L"'while' block" )
/** /**
For block description For block description
*/ */
#define FOR_BLOCK _( L"'for' block" ) #define FOR_BLOCK N_( L"'for' block" )
/** /**
If block description If block description
*/ */
#define IF_BLOCK _( L"'if' conditional block" ) #define IF_BLOCK N_( L"'if' conditional block" )
/** /**
Function definition block description Function definition block description
*/ */
#define FUNCTION_DEF_BLOCK _( L"function definition block" ) #define FUNCTION_DEF_BLOCK N_( L"function definition block" )
/** /**
Function invocation block description Function invocation block description
*/ */
#define FUNCTION_CALL_BLOCK _( L"function invocation block" ) #define FUNCTION_CALL_BLOCK N_( L"function invocation block" )
/** /**
Switch block description Switch block description
*/ */
#define SWITCH_BLOCK _( L"'switch' block" ) #define SWITCH_BLOCK N_( L"'switch' block" )
/** /**
Fake block description Fake block description
*/ */
#define FAKE_BLOCK _( L"unexecutable block" ) #define FAKE_BLOCK N_( L"unexecutable block" )
/** /**
Top block description Top block description
*/ */
#define TOP_BLOCK _( L"global root block" ) #define TOP_BLOCK N_( L"global root block" )
/** /**
Command substitution block description Command substitution block description
*/ */
#define SUBST_BLOCK _( L"command substitution block" ) #define SUBST_BLOCK N_( L"command substitution block" )
/** /**
Begin block description Begin block description
*/ */
#define BEGIN_BLOCK _( L"'begin' unconditional block" ) #define BEGIN_BLOCK N_( L"'begin' unconditional block" )
/** /**
Source block description Source block description
*/ */
#define SOURCE_BLOCK _( L"Block created by the . builtin" ) #define SOURCE_BLOCK N_( L"Block created by the . builtin" )
/** /**
Source block description Source block description
*/ */
#define EVENT_BLOCK _( L"event handler block" ) #define EVENT_BLOCK N_( L"event handler block" )
/** /**
Unknown block description Unknown block description
*/ */
#define UNKNOWN_BLOCK _( L"unknown/invalid block" ) #define UNKNOWN_BLOCK N_( L"unknown/invalid block" )
/** /**
@ -256,6 +256,71 @@ The fish parser. Contains functions for parsing code.
*/ */
#define ERR_STR_SZ 1024 #define ERR_STR_SZ 1024
struct block_lookup_entry
{
int type;
const wchar_t *name;
const wchar_t *desc;
}
;
const static struct block_lookup_entry block_lookup[]=
{
{
WHILE, L"while", WHILE_BLOCK
}
,
{
FOR, L"for", FOR_BLOCK
}
,
{
IF, L"if", IF_BLOCK
}
,
{
FUNCTION_DEF, L"function", FUNCTION_DEF_BLOCK
}
,
{
FUNCTION_CALL, 0, FUNCTION_CALL_BLOCK
}
,
{
SWITCH, L"switch", SWITCH_BLOCK
}
,
{
FAKE, 0, FAKE_BLOCK
}
,
{
TOP, 0, TOP_BLOCK
}
,
{
SUBST, 0, SUBST_BLOCK
}
,
{
BEGIN, L"begin", BEGIN_BLOCK
}
,
{
SOURCE, L".", SOURCE_BLOCK
}
,
{
EVENT, 0, EVENT_BLOCK
}
,
{
0,0,0
}
}
;
/** Last error code */ /** Last error code */
static int error_code; static int error_code;
@ -393,48 +458,16 @@ void parser_pop_block()
const wchar_t *parser_get_block_desc( int block ) const wchar_t *parser_get_block_desc( int block )
{ {
switch( block ) int i;
for( i=0; block_lookup[i].desc; i++ )
{ {
case WHILE: if( block_lookup[i].type == block )
return WHILE_BLOCK; {
return _( block_lookup[i].desc );
case FOR:
return FOR_BLOCK;
case IF:
return IF_BLOCK;
case FUNCTION_DEF:
return FUNCTION_DEF_BLOCK;
case FUNCTION_CALL:
return FUNCTION_CALL_BLOCK;
case SWITCH:
return SWITCH_BLOCK;
case FAKE:
return FAKE_BLOCK;
case TOP:
return TOP_BLOCK;
case SUBST:
return SUBST_BLOCK;
case BEGIN:
return BEGIN_BLOCK;
case SOURCE:
return SOURCE_BLOCK;
case EVENT:
return EVENT_BLOCK;
default:
return UNKNOWN_BLOCK;
} }
}
return _(UNKNOWN_BLOCK);
} }
/** /**
@ -1769,6 +1802,9 @@ static int parse_job( process_t *p,
while( al_get_count( args ) == 0 ) while( al_get_count( args ) == 0 )
{ {
wchar_t *nxt=0; wchar_t *nxt=0;
int consumed = 0; // Set to one if the command requires a second command, like e.g. while does
int mark; // Use to save the position of the beginning of the token
switch( tok_last_type( tok )) switch( tok_last_type( tok ))
{ {
case TOK_STRING: case TOK_STRING:
@ -1835,11 +1871,13 @@ static int parse_job( process_t *p,
} }
} }
int mark = tok_get_pos( tok ); mark = tok_get_pos( tok );
int consumed = 0;
/*
Test if this command is one of the many special builtins
that work directly on the parser, like e.g. 'not', that
simply flips the status inversion flag in the job.
*/
if( wcscmp( L"command", nxt )==0 ) if( wcscmp( L"command", nxt )==0 )
{ {
tok_next( tok ); tok_next( tok );
@ -1973,8 +2011,14 @@ static int parse_job( process_t *p,
consumed=1; consumed=1;
} }
/*
Test if we need another command
*/
if( consumed ) if( consumed )
{ {
/*
Yes we do, around in the loop for another lap, then!
*/
continue; continue;
} }
@ -2624,27 +2668,41 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type )
return code; return code;
} }
/** /**
\return the block type created by the specified builtin, or -1 on error. \return the block type created by the specified builtin, or -1 on error.
*/ */
static int parser_get_block_type( const wchar_t *cmd ) static int parser_get_block_type( const wchar_t *cmd )
{ {
if( wcscmp( cmd, L"while") == 0 ) int i;
return WHILE;
else if( wcscmp( cmd, L"for") == 0 ) for( i=0; block_lookup[i].desc; i++ )
return FOR; {
else if( wcscmp( cmd, L"switch") == 0 ) if( block_lookup[i].name && (wcscmp( block_lookup[i].name, cmd ) == 0) )
return SWITCH; {
else if( wcscmp( cmd, L"if") == 0 ) return block_lookup[i].type;
return IF; }
else if( wcscmp( cmd, L"function") == 0 ) }
return FUNCTION_DEF;
else if( wcscmp( cmd, L"begin") == 0 )
return BEGIN;
else
return -1; return -1;
} }
/**
\return the block type created by the specified builtin, or -1 on error.
*/
static const wchar_t *parser_get_block_command( int type )
{
int i;
for( i=0; block_lookup[i].desc; i++ )
{
if( block_lookup[i].type == type )
{
return block_lookup[i].name;
}
}
return 0;
}
/** /**
Test if this argument contains any errors. Detected errors include Test if this argument contains any errors. Detected errors include
syntax errors in command substitutions, imporoper escaped syntax errors in command substitutions, imporoper escaped
@ -3167,10 +3225,15 @@ int parser_test( const wchar_t * buff,
err = 1; err = 1;
if( out ) if( out )
{ {
char *h;
error( SYNTAX_ERROR, error( SYNTAX_ERROR,
tok_get_pos( &tok ), tok_get_pos( &tok ),
INVALID_END_ERR_MSG ); INVALID_END_ERR_MSG );
print_errors( out, prefix ); print_errors( out, prefix );
h = builtin_help_get( L"end" );
if( h )
sb_printf( out, L"%s", h );
} }
} }
} }
@ -3373,10 +3436,26 @@ int parser_test( const wchar_t * buff,
if( out && count>0 ) if( out && count>0 )
{ {
const char *h;
const wchar_t *cmd;
error( SYNTAX_ERROR, error( SYNTAX_ERROR,
block_pos[count-1], block_pos[count-1],
BLOCK_END_ERR_MSG ); BLOCK_END_ERR_MSG );
print_errors( out, prefix ); print_errors( out, prefix );
cmd = parser_get_block_command( block_type[count -1] );
if( cmd )
{
h = builtin_help_get( cmd );
if( cmd )
{
sb_printf( out, L"%s", h );
}
}
} }
tok_destroy( &tok ); tok_destroy( &tok );