diff --git a/builtin.cpp b/builtin.cpp index 362b01ede..f20e1f12d 100644 --- a/builtin.cpp +++ b/builtin.cpp @@ -842,8 +842,8 @@ static int builtin_block( parser_t &parser, wchar_t **argv ) case UNSET: { while( block && - block->type != FUNCTION_CALL && - block->type != FUNCTION_CALL_NO_SHADOW ) + block->type() != FUNCTION_CALL && + block->type() != FUNCTION_CALL_NO_SHADOW ) block = block->outer; } } @@ -1530,8 +1530,7 @@ static int builtin_function( parser_t &parser, wchar_t **argv ) woptind=0; - block_t *newv = new block_t(FUNCTION_DEF); - parser.push_block( newv ); + parser.push_block( new function_def_block_t() ); static const struct woption long_options[] = @@ -1663,7 +1662,7 @@ static int builtin_function( parser_t &parser, wchar_t **argv ) { block_t *b = parser.current_block; - while( b && (b->type != SUBST) ) + while( b && (b->type() != SUBST) ) b = b->outer; if( b ) @@ -1730,7 +1729,7 @@ static int builtin_function( parser_t &parser, wchar_t **argv ) case 'h': parser.pop_block(); - parser.push_block( new block_t(FAKE) ); + parser.push_block( new fake_block_t() ); builtin_print_help( parser, argv[0], stdout_buffer ); return STATUS_BUILTIN_OK; @@ -1835,7 +1834,7 @@ static int builtin_function( parser_t &parser, wchar_t **argv ) stderr_buffer.push_back(L'\n'); parser.pop_block(); - parser.push_block( new block_t(FAKE) ); + parser.push_block( new fake_block_t() ); } else { @@ -3204,7 +3203,7 @@ static int builtin_for( parser_t &parser, wchar_t **argv ) if( res ) { - parser.push_block( new block_t(FAKE) ); + parser.push_block( new fake_block_t() ); } else { @@ -3235,7 +3234,7 @@ static int builtin_for( parser_t &parser, wchar_t **argv ) */ static int builtin_begin( parser_t &parser, wchar_t **argv ) { - parser.push_block( new block_t(BEGIN) ); + parser.push_block( new scope_block_t(BEGIN) ); parser.current_block->tok_pos = parser.get_pos(); return proc_get_last_status(); } @@ -3266,7 +3265,7 @@ static int builtin_end( parser_t &parser, wchar_t **argv ) */ int kill_block = 1; - switch( parser.current_block->type ) + switch( parser.current_block->type() ) { case WHILE: { @@ -3290,6 +3289,7 @@ static int builtin_end( parser_t &parser, wchar_t **argv ) case IF: case SUBST: case BEGIN: + case SWITCH: /* Nothing special happens at the end of these commands. The scope just ends. */ @@ -3364,6 +3364,10 @@ static int builtin_end( parser_t &parser, wchar_t **argv ) } break; + + default: + assert(false); //should never get here + break; } if( kill_block ) @@ -3385,7 +3389,7 @@ static int builtin_else( parser_t &parser, wchar_t **argv ) { bool block_ok = false; if_block_t *if_block = NULL; - if (parser.current_block != NULL && parser.current_block->type == IF) + if (parser.current_block != NULL && parser.current_block->type() == IF) { if_block = static_cast(parser.current_block); if (if_block->if_expr_evaluated && ! if_block->else_evaluated) @@ -3441,8 +3445,8 @@ static int builtin_break_continue( parser_t &parser, wchar_t **argv ) while( (b != 0) && - ( b->type != WHILE) && - (b->type != FOR ) ) + ( b->type() != WHILE) && + (b->type() != FOR ) ) { b = b->outer; } @@ -3457,8 +3461,8 @@ static int builtin_break_continue( parser_t &parser, wchar_t **argv ) } b = parser.current_block; - while( ( b->type != WHILE) && - (b->type != FOR ) ) + while( ( b->type() != WHILE) && + (b->type() != FOR ) ) { b->skip=1; b = b->outer; @@ -3475,7 +3479,7 @@ static int builtin_break_continue( parser_t &parser, wchar_t **argv ) static int builtin_breakpoint( parser_t &parser, wchar_t **argv ) { - parser.push_block( new block_t(BREAKPOINT) ); + parser.push_block( new breakpoint_block_t() ); reader_read( STDIN_FILENO, real_io ? *real_io : io_chain_t() ); @@ -3525,8 +3529,8 @@ static int builtin_return( parser_t &parser, wchar_t **argv ) while( (b != 0) && - ( b->type != FUNCTION_CALL && - b->type != FUNCTION_CALL_NO_SHADOW) ) + ( b->type() != FUNCTION_CALL && + b->type() != FUNCTION_CALL_NO_SHADOW) ) { b = b->outer; } @@ -3541,10 +3545,10 @@ static int builtin_return( parser_t &parser, wchar_t **argv ) } b = parser.current_block; - while( ( b->type != FUNCTION_CALL && - b->type != FUNCTION_CALL_NO_SHADOW ) ) + while( ( b->type() != FUNCTION_CALL && + b->type() != FUNCTION_CALL_NO_SHADOW ) ) { - b->type = FAKE; + b->mark_as_fake(); b->skip=1; b = b->outer; } @@ -3571,7 +3575,7 @@ static int builtin_switch( parser_t &parser, wchar_t **argv ) builtin_print_help( parser, argv[0], stderr_buffer ); res=1; - parser.push_block( new block_t(FAKE) ); + parser.push_block( new fake_block_t() ); } else { @@ -3593,7 +3597,7 @@ static int builtin_case( parser_t &parser, wchar_t **argv ) int i; wchar_t *unescaped=0; - if( parser.current_block->type != SWITCH ) + if( parser.current_block->type() != SWITCH ) { append_format(stderr_buffer, _( L"%ls: 'case' command while not in switch block\n" ), diff --git a/parser.cpp b/parser.cpp index c55c83349..bc1d69614 100644 --- a/parser.cpp +++ b/parser.cpp @@ -422,13 +422,13 @@ static int block_count( block_t *b ) void parser_t::push_block( block_t *newv ) { - const int type = newv->type; + const enum block_type_t type = newv->type(); newv->src_lineno = parser_t::get_lineno(); newv->src_filename = parser_t::current_filename()?intern(parser_t::current_filename()):0; newv->outer = current_block; if (current_block && current_block->skip) - newv->type = FAKE; + newv->mark_as_fake(); /* New blocks should be skipped if the outer block is skipped, @@ -458,9 +458,9 @@ void parser_t::push_block( block_t *newv ) current_block = newv; - if( (newv->type != FUNCTION_DEF) && - (newv->type != FAKE) && - (newv->type != TOP) ) + if( (newv->type() != FUNCTION_DEF) && + (newv->type() != FAKE) && + (newv->type() != TOP) ) { env_push( type == FUNCTION_CALL ); newv->wants_pop_env = true; @@ -887,7 +887,7 @@ void parser_t::stack_trace( block_t *b, wcstring &buff) if( !b ) return; - if( b->type==EVENT ) + if( b->type()==EVENT ) { /* This is an event handler @@ -908,7 +908,7 @@ void parser_t::stack_trace( block_t *b, wcstring &buff) return; } - if( b->type == FUNCTION_CALL || b->type==SOURCE || b->type==SUBST) + if( b->type() == FUNCTION_CALL || b->type()==SOURCE || b->type()==SUBST) { /* These types of blocks should be printed @@ -916,7 +916,7 @@ void parser_t::stack_trace( block_t *b, wcstring &buff) int i; - switch( b->type) + switch( b->type()) { case SOURCE: { @@ -936,6 +936,9 @@ void parser_t::stack_trace( block_t *b, wcstring &buff) append_format( buff, _(L"in command substitution\n") ); break; } + + default: /* Can't get here */ + break; } const wchar_t *file = b->src_filename; @@ -953,7 +956,7 @@ void parser_t::stack_trace( block_t *b, wcstring &buff) _(L"\tcalled on standard input,\n") ); } - if( b->type == FUNCTION_CALL ) + if( b->type() == FUNCTION_CALL ) { const function_block_t *fb = static_cast(b); const process_t * const process = fb->process; @@ -999,7 +1002,7 @@ const wchar_t *parser_t::is_function() const { return NULL; } - if( b->type == FUNCTION_CALL ) + if( b->type() == FUNCTION_CALL ) { const function_block_t *fb = static_cast(b); return fb->name.c_str(); @@ -1051,7 +1054,7 @@ const wchar_t *parser_t::current_filename() const { return reader_current_filename(); } - if( b->type == FUNCTION_CALL ) + if( b->type() == FUNCTION_CALL ) { const function_block_t *fb = static_cast(b); return function_get_definition_file(fb->name); @@ -1403,7 +1406,7 @@ void parser_t::parse_job_argument_list( process_t *p, But if this is in fact a case statement, then it should be evaluated */ - if( (current_block->type == SWITCH) && args.at(0).completion == L"case" && p->type == INTERNAL_BUILTIN ) + if( (current_block->type() == SWITCH) && args.at(0).completion == L"case" && p->type == INTERNAL_BUILTIN ) { skip=0; } @@ -1855,7 +1858,7 @@ int parser_t::parse_job( process_t *p, tok_next( tok ); while_block_t *wb = NULL; - if( ( current_block->type != WHILE ) ) + if( ( current_block->type() != WHILE ) ) { new_block = true; } @@ -1917,9 +1920,9 @@ int parser_t::parse_job( process_t *p, block scopes are pushed on function invocation changes, then this check will break. */ - if( ( current_block->type == TOP ) && + if( ( current_block->type() == TOP ) && ( current_block->outer ) && - ( current_block->outer->type == FUNCTION_CALL ) ) + ( current_block->outer->type() == FUNCTION_CALL ) ) is_function_call = 1; /* @@ -2210,7 +2213,7 @@ int parser_t::parse_job( process_t *p, { if( !is_new_block ) { - current_block->had_command = 1; + current_block->had_command = true; } } @@ -2249,7 +2252,7 @@ void parser_t::skipped_exec( job_t * j ) ( wcscmp( p->argv0(), L"begin" )==0) || ( wcscmp( p->argv0(), L"function" )==0)) { - this->push_block( new block_t(FAKE) ); + this->push_block( new fake_block_t() ); } else if( wcscmp( p->argv0(), L"end" )==0) { @@ -2262,7 +2265,7 @@ void parser_t::skipped_exec( job_t * j ) } else if( wcscmp( p->argv0(), L"else" )==0) { - if( (current_block->type == IF ) && + if( (current_block->type() == IF ) && (static_cast(current_block)->if_expr_evaluated)) { exec( *this, j ); @@ -2271,7 +2274,7 @@ void parser_t::skipped_exec( job_t * j ) } else if( wcscmp( p->argv0(), L"case" )==0) { - if(current_block->type == SWITCH) + if(current_block->type() == SWITCH) { exec( *this, j ); return; @@ -2395,7 +2398,7 @@ void parser_t::eval_job( tokenizer *tok ) profile_item->exec=(int)(t3-t2); } - if( current_block->type == WHILE ) + if( current_block->type() == WHILE ) { while_block_t *wb = static_cast(current_block); switch( wb->status ) @@ -2411,7 +2414,7 @@ void parser_t::eval_job( tokenizer *tok ) } } - if( current_block->type == IF ) + if( current_block->type() == IF ) { if_block_t *ib = static_cast(current_block); if( (! ib->if_expr_evaluated) && @@ -2543,7 +2546,7 @@ int parser_t::eval( const wcstring &cmdStr, const io_chain_t &io, enum block_typ eval_level++; - this->push_block( new block_t(block_type) ); + this->push_block( new scope_block_t(block_type) ); current_tokenizer = new tokenizer; tok_init( current_tokenizer, cmd, 0 ); @@ -2580,7 +2583,7 @@ int parser_t::eval( const wcstring &cmdStr, const io_chain_t &io, enum block_typ //debug( 2, L"Status %d\n", proc_get_last_status() ); debug( 1, - L"%ls", parser_t::get_block_desc( current_block->type ) ); + L"%ls", parser_t::get_block_desc( current_block->type() ) ); debug( 1, BLOCK_END_ERR_MSG ); fwprintf( stderr, L"%ls", parser_t::current_line() ); @@ -3617,16 +3620,15 @@ int parser_t::test( const wchar_t * buff, } -block_t::block_t(int t) : - type(t), +block_t::block_t(block_type_t t) : + block_type(t), + made_fake(false), skip(), - tok_pos(), had_command(), + tok_pos(), loop_status(), job(), function_data(), - state1_ptr(), - state2_ptr(), src_filename(), src_lineno(), wants_pop_env(false), @@ -3637,8 +3639,74 @@ block_t::block_t(int t) : block_t::~block_t() { - if (state1_ptr != NULL) - delete state1_ptr; - if (state2_ptr != NULL) - delete state2_ptr; +} + +/* Various block constructors */ + +if_block_t::if_block_t() : + if_expr_evaluated(false), + if_expr_result(false), + else_evaluated(false), + block_t(IF) +{ +} + +event_block_t::event_block_t(const event_t *evt) : + block_t(EVENT), + event(evt) +{ +} + +function_block_t::function_block_t(process_t *p, const wcstring &n, bool shadows) : + process(p), + name(n), + block_t( shadows ? FUNCTION_CALL : FUNCTION_CALL_NO_SHADOW ) +{ +} + +source_block_t::source_block_t(const wchar_t *src) : + source_file(src), + block_t(SOURCE) +{ +} + +for_block_t::for_block_t(const wcstring &var) : + variable(var), + sequence(), + block_t(FOR) +{ +} + +while_block_t::while_block_t() : + status(0), + block_t(WHILE) +{ +} + +switch_block_t::switch_block_t(const wcstring &sv) : + switch_taken(false), + switch_value(sv), + block_t(SWITCH) +{ +} + +fake_block_t::fake_block_t() : + block_t(FAKE) +{ +} + +function_def_block_t::function_def_block_t() : + block_t(FUNCTION_DEF) +{ +} + +scope_block_t::scope_block_t(block_type_t type) : + block_t(type) +{ + assert(type == BEGIN || type == TOP || type == SUBST); +} + +breakpoint_block_t::breakpoint_block_t() : + block_t(BREAKPOINT) +{ } diff --git a/parser.h b/parser.h index d968ea20b..6e00adcfd 100644 --- a/parser.h +++ b/parser.h @@ -68,27 +68,28 @@ enum block_type_t } ; -/** Block state template, to replace the discriminated union */ -struct block_state_base_t { - public: - virtual ~block_state_base_t() {} -}; - -template -struct block_state_t : public block_state_base_t { - T value; - block_state_t() : value() {} -}; - /** block_t represents a block of commands. */ struct block_t { - int type; /**< Type of block. Can be one of WHILE, FOR, IF and FUNCTION, or FAKE */ - int skip; /**< Whether execution of the commands in this block should be skipped */ + 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 */ int tok_pos; /**< The start index of the block */ - int had_command; /**< Set to non-zero once a command has been executed in this block */ /** Status for the current loop block. Can be any of the values from the loop_status enum. @@ -118,41 +119,6 @@ struct block_t } param1; #endif - /** First block type specific variable */ - block_state_base_t *state1_ptr; - - template - T& state1_NOPE(void) { - block_state_t *state; - if (state1_ptr == NULL) { - state = new block_state_t(); - state1_ptr = state; - } else { - state = dynamic_cast *>(state1_ptr); - if (state == NULL) { - printf("Expected type %s, but instead got type %s\n", typeid(T).name(), typeid(*state1_ptr).name()); - abort(); - } - } - return state->value; - } - - /** Second block type specific variable */ - block_state_base_t *state2_ptr; - - template - T& state2_NOPE(void) { - block_state_t *state; - if (state2_ptr == NULL) { - state = new block_state_t(); - state2_ptr = state; - } else { - state = dynamic_cast *>(state2_ptr); - assert(state != NULL); - } - return state->value; - } - /** Name of file that created this block */ @@ -173,10 +139,7 @@ struct block_t Next outer block */ block_t *outer; - - /** Constructor */ - block_t(int t); - + /** Destructor */ virtual ~block_t(); }; @@ -185,65 +148,56 @@ struct if_block_t : public block_t { 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 - if_block_t() : - if_expr_evaluated(false), - if_expr_result(false), - else_evaluated(false), - block_t(IF) - { - } + if_block_t(); }; struct event_block_t : public block_t { const event_t * const event; - event_block_t(const event_t *evt) : block_t(EVENT), event(evt) - { - } + event_block_t(const event_t *evt); }; struct function_block_t : public block_t { process_t *process; wcstring name; - - function_block_t(process_t *p, const wcstring &n, bool shadows) : - process(p), - name(n), - block_t( shadows ? FUNCTION_CALL : FUNCTION_CALL_NO_SHADOW ) - { - } + function_block_t(process_t *p, const wcstring &n, bool shadows); }; struct source_block_t : public block_t { const wchar_t * const source_file; - source_block_t(const wchar_t *src) : source_file(src), block_t(SOURCE) - { - } + source_block_t(const wchar_t *src); }; 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) : - variable(var), - sequence(), - block_t(FOR) - { - } + for_block_t(const wcstring &var); }; struct while_block_t : public block_t { int status; - while_block_t() : status(0), block_t(WHILE) - { - } + while_block_t(); }; struct switch_block_t : public block_t { bool switch_taken; const wcstring switch_value; - switch_block_t(const wcstring &sv) : switch_taken(false), switch_value(sv), block_t(SWITCH) - { - } + switch_block_t(const wcstring &sv); +}; + +struct fake_block_t : public block_t { + fake_block_t(); +}; + +struct function_def_block_t : public block_t { + function_def_block_t(); +}; + +struct scope_block_t : public block_t { + scope_block_t(block_type_t type); //must be BEGIN, TOP or SUBST +}; + +struct breakpoint_block_t : public block_t { + breakpoint_block_t(); }; /** diff --git a/reader.cpp b/reader.cpp index a245d1c3f..4445d0886 100644 --- a/reader.cpp +++ b/reader.cpp @@ -2390,7 +2390,7 @@ static void handle_end_loop() b; b = b->outer ) { - if( b->type == BREAKPOINT ) + if( b->type() == BREAKPOINT ) { is_breakpoint = 1; break;