# HG changeset patch # User John W. Eaton # Date 1367954940 14400 # Node ID de91b1621260e81d66f6fa7bd4546f93f20a2b9e # Parent 4adf3c4bd80bd1993f38ba056fd58f04d013c2b9 adjust location of eof marker for files with subfunctions but no explicit end statements * ov-fcn.h (octave_function::maybe_relocate_end, octave_function::has_subfunctions, octave_function::stash_subfunction_names, octave_function::subfunction_names): New virtual functions. * ov-usr-fcn.h, ov-usr-fcn.cc (octave_user_function::end_location_line, octave_user_function::end_location_column, octave_user_function::subfcn_names): New member variables. (octave_user_function::beginning_line, octave_user_function::beginning_column, octave_user_function::stash_fcn_end_location, octave_user_function::ending_line, octave_user_function::ending_column, octave_user_function::has_subfunctions, octave_user_function::subfunction_names, octave_user_function::stash_subfunction_names, octave_user_function::maybe_relocate_end_internal, octave_user_function::maybe_relocate_end): New functions. * oct-parse.in.yy (FCN): Declare as token with tok_val type. (function_beg): Declare as tok_val type. Return FCN value. (function): Move stash_comment here from function_beg. Pass line and column info to parser.finish_function. (octave_base_parser::subfunction_names): New data member. (octave_base_parser::reset): Clear subfuntction_names. (octave_base_parser::start_function): Call stash_fcn_end_location. (octave_base_parser::frob_function): Don't call stash_fcn_location. (octave_base_parser_::finish_function): Call stash_fcn_location. Append name to subfunction_names. Call maybe_relocate_end on constructed function. (parse_fcn_file): Attach subfunction names to primary function. * pt-stmt.h, pt-stmt.cc (tree_statement::set_location): New function. * pt.h (tree::set_location): New function. * pt-cmd.h, pt-cmd.cc (tree_no_op_command::tree_no_op_command): Use EOF member variable to track auto-generated end statements that appear at the end of file. Change all callers. (tree_command::is_end_of_file): New function. * pt-stmt.h, pt-stmt.cc (tree_statement::set_location, tree_statement::is_end_of_file): New functions. * base-list.h (octave_base_list::reverse_iterator, octave_base_list::const_reverse_iterator): New typedefs. (octave_base_list::rbegin, octave_base_list::rend): New functions. * debug.h, debug.cc (bp_table::do_add_breakpoint): Handle subfunctions. (bp_table::do_remove_breakpoint_1): New function. (bp_table::do_remove_breakpoint): Use it. Handle subfunctions. (bp_table::do_remove_all_breakpoints_in_file_1): New function. (bp_table::do_remove_all_breakpoints_in_file): Use it. Handle subfunctions. diff -r 4adf3c4bd80b -r de91b1621260 libinterp/interpfcn/debug.cc --- a/libinterp/interpfcn/debug.cc Mon May 06 20:02:08 2013 -0400 +++ b/libinterp/interpfcn/debug.cc Tue May 07 15:29:00 2013 -0400 @@ -316,19 +316,27 @@ { if (! do_add_breakpoint_1 (dbg_fcn, fname, line, retval)) { - typedef std::map::const_iterator - subfunction_map_const_iterator; + // Search subfunctions in the order they appear in the file. + + const std::list subfcn_names + = dbg_fcn->subfunction_names (); std::map subfcns = dbg_fcn->subfunctions (); - for (subfunction_map_const_iterator p = subfcns.begin (); - p != subfcns.end (); p++) + for (std::list::const_iterator p = subfcn_names.begin (); + p != subfcn_names.end (); p++) { - octave_user_code *dbg_subfcn = p->second.user_code_value (); + std::map::const_iterator + q = subfcns.find (*p); - if (do_add_breakpoint_1 (dbg_subfcn, fname, line, retval)) - break; + if (q != subfcns.end ()) + { + octave_user_code *dbg_subfcn = q->second.user_code_value (); + + if (do_add_breakpoint_1 (dbg_subfcn, fname, line, retval)) + break; + } } } } @@ -342,6 +350,56 @@ int +bp_table::do_remove_breakpoint_1 (octave_user_code *fcn, + const std::string& fname, + const bp_table::intmap& line) +{ + int retval = 0; + + std::string file = fcn->fcn_file_name (); + + tree_statement_list *cmds = fcn->body (); + + // FIXME -- move the operation on cmds to the + // tree_statement_list class? + + if (cmds) + { + octave_value_list results = cmds->list_breakpoints (); + + if (results.length () > 0) + { + octave_idx_type len = line.size (); + + for (int i = 0; i < len; i++) + { + const_intmap_iterator p = line.find (i); + + if (p != line.end ()) + { + int lineno = p->second; + + cmds->delete_breakpoint (lineno); + + if (! file.empty ()) + octave_link::update_breakpoint (false, file, lineno); + } + } + + results = cmds->list_breakpoints (); + + bp_set_iterator it = bp_set.find (fname); + if (results.length () == 0 && it != bp_set.end ()) + bp_set.erase (it); + } + + retval = results.length (); + } + + return retval; +} + +int bp_table::do_remove_breakpoint (const std::string& fname, const bp_table::intmap& line) { @@ -360,41 +418,28 @@ if (dbg_fcn) { - std::string file = dbg_fcn->fcn_file_name (); + retval = do_remove_breakpoint_1 (dbg_fcn, fname, line); - tree_statement_list *cmds = dbg_fcn->body (); + // Search subfunctions in the order they appear in the file. - // FIXME -- move the operation on cmds to the - // tree_statement_list class? - if (cmds) - { - octave_value_list results = cmds->list_breakpoints (); + const std::list subfcn_names + = dbg_fcn->subfunction_names (); - if (results.length () > 0) - { - for (int i = 0; i < len; i++) - { - const_intmap_iterator p = line.find (i); + std::map subfcns + = dbg_fcn->subfunctions (); - if (p != line.end ()) - { - int lineno = p->second; - - cmds->delete_breakpoint (lineno); + for (std::list::const_iterator p = subfcn_names.begin (); + p != subfcn_names.end (); p++) + { + std::map::const_iterator + q = subfcns.find (*p); - if (! file.empty ()) - octave_link::update_breakpoint (false, file, lineno); - } - } - - results = cmds->list_breakpoints (); + if (q != subfcns.end ()) + { + octave_user_code *dbg_subfcn = q->second.user_code_value (); - bp_set_iterator it = bp_set.find (fname); - if (results.length () == 0 && it != bp_set.end ()) - bp_set.erase (it); + retval += do_remove_breakpoint_1 (dbg_subfcn, fname, line); } - - retval = results.length (); } } else @@ -406,6 +451,27 @@ return retval; } +bp_table::intmap +bp_table::do_remove_all_breakpoints_in_file_1 (octave_user_code *fcn, + const std::string& fname) +{ + intmap retval; + + std::string file = fcn->fcn_file_name (); + + tree_statement_list *cmds = fcn->body (); + + if (cmds) + { + retval = cmds->remove_all_breakpoints (file); + + bp_set_iterator it = bp_set.find (fname); + if (it != bp_set.end ()) + bp_set.erase (it); + } + + return retval; +} bp_table::intmap bp_table::do_remove_all_breakpoints_in_file (const std::string& fname, @@ -417,17 +483,24 @@ if (dbg_fcn) { - std::string file = dbg_fcn->fcn_file_name (); + retval = do_remove_all_breakpoints_in_file_1 (dbg_fcn, fname); + + // Order is not important here. - tree_statement_list *cmds = dbg_fcn->body (); + typedef std::map::const_iterator + subfcns_const_iterator; - if (cmds) + std::map subfcns = dbg_fcn->subfunctions (); + + for (subfcns_const_iterator p = subfcns.begin (); + p != subfcns.end (); p++) { - retval = cmds->remove_all_breakpoints (file); + octave_user_code *dbg_subfcn = p->second.user_code_value (); - bp_set_iterator it = bp_set.find (fname); - if (it != bp_set.end ()) - bp_set.erase (it); + intmap tmp = do_remove_all_breakpoints_in_file_1 (dbg_subfcn, fname); + + // Merge new list with retval. + retval.insert (tmp.begin (), tmp.end ()); } } else if (! silent) diff -r 4adf3c4bd80b -r de91b1621260 libinterp/interpfcn/debug.h --- a/libinterp/interpfcn/debug.h Mon May 06 20:02:08 2013 -0400 +++ b/libinterp/interpfcn/debug.h Tue May 07 15:29:00 2013 -0400 @@ -120,8 +120,14 @@ intmap do_add_breakpoint (const std::string& fname, const intmap& lines); + int do_remove_breakpoint_1 (octave_user_code *fcn, const std::string&, + const intmap& lines); + int do_remove_breakpoint (const std::string&, const intmap& lines); + intmap do_remove_all_breakpoints_in_file_1 (octave_user_code *fcn, + const std::string& fname); + intmap do_remove_all_breakpoints_in_file (const std::string& fname, bool silent); diff -r 4adf3c4bd80b -r de91b1621260 libinterp/octave-value/ov-fcn.h --- a/libinterp/octave-value/ov-fcn.h Mon May 06 20:02:08 2013 -0400 +++ b/libinterp/octave-value/ov-fcn.h Tue May 07 15:29:00 2013 -0400 @@ -134,6 +134,18 @@ virtual void unlock_subfunctions (void) { } + virtual void maybe_relocate_end (void) { } + + // Not valid until after the function is completley parsed. + virtual bool has_subfunctions (void) const { return false; } + + virtual void stash_subfunction_names (const std::list&) { } + + virtual std::list subfunction_names (void) const + { + return std::list (); + } + void mark_relative (void) { relative = true; } bool is_relative (void) const { return relative; } diff -r 4adf3c4bd80b -r de91b1621260 libinterp/octave-value/ov-usr-fcn.cc --- a/libinterp/octave-value/ov-usr-fcn.cc Mon May 06 20:02:08 2013 -0400 +++ b/libinterp/octave-value/ov-usr-fcn.cc Tue May 07 15:29:00 2013 -0400 @@ -248,6 +248,70 @@ file_name = nm; } +// If there is no explicit end statement at the end of the function, +// relocate the no_op that was generated for the end of file condition +// to appear on the next line after the last statement in the file, or +// the next line after the function keyword if there are no statements. +// More precisely, the new location should probably be on the next line +// after the end of the parameter list, but we aren't tracking that +// information (yet). + +void +octave_user_function::maybe_relocate_end_internal (void) +{ + if (cmd_list && ! cmd_list->empty ()) + { + tree_statement *last_stmt = cmd_list->back (); + + if (last_stmt && last_stmt->is_end_of_fcn_or_script () + && last_stmt->is_end_of_file ()) + { + tree_statement_list::reverse_iterator + next_to_last_elt = cmd_list->rbegin (); + + next_to_last_elt++; + + int new_eof_line; + int new_eof_col; + + if (next_to_last_elt == cmd_list->rend ()) + { + new_eof_line = beginning_line (); + new_eof_col = beginning_column (); + } + else + { + tree_statement *next_to_last_stmt = *next_to_last_elt; + + new_eof_line = next_to_last_stmt->line (); + new_eof_col = next_to_last_stmt->column (); + } + + last_stmt->set_location (new_eof_line + 1, new_eof_col); + } + } +} + +void +octave_user_function::maybe_relocate_end (void) +{ + std::map fcns = subfunctions (); + + if (! fcns.empty ()) + { + for (std::map::iterator p = fcns.begin (); + p != fcns.end (); p++) + { + octave_user_function *f = (p->second).user_function_value (); + + if (f) + f->maybe_relocate_end_internal (); + } + } + + maybe_relocate_end_internal (); +} + std::string octave_user_function::profiler_name (void) const { @@ -320,6 +384,19 @@ return symbol_table::subfunctions_defined_in_scope (local_scope); } +bool +octave_user_function::has_subfunctions (void) const +{ + return ! subfcn_names.empty (); +} + +void +octave_user_function::stash_subfunction_names + (const std::list& names) +{ + subfcn_names = names; +} + octave_value_list octave_user_function::all_va_args (const octave_value_list& args) { diff -r 4adf3c4bd80b -r de91b1621260 libinterp/octave-value/ov-usr-fcn.h --- a/libinterp/octave-value/ov-usr-fcn.h Mon May 06 20:02:08 2013 -0400 +++ b/libinterp/octave-value/ov-usr-fcn.h Tue May 07 15:29:00 2013 -0400 @@ -208,6 +208,20 @@ location_column = col; } + int beginning_line (void) const { return location_line; } + int beginning_column (void) const { return location_column; } + + void stash_fcn_end_location (int line, int col) + { + end_location_line = line; + end_location_column = col; + } + + int ending_line (void) const { return end_location_line; } + int ending_column (void) const { return end_location_column; } + + void maybe_relocate_end (void); + void stash_parent_fcn_name (const std::string& p) { parent_name = p; } void stash_parent_fcn_scope (symbol_table::scope_id ps) { parent_scope = ps; } @@ -266,6 +280,15 @@ std::map subfunctions (void) const; + bool has_subfunctions (void) const; + + void stash_subfunction_names (const std::list& names); + + std::list subfunction_names (void) const + { + return subfcn_names; + } + octave_value_list all_va_args (const octave_value_list& args); void stash_function_name (const std::string& s) { my_name = s; } @@ -406,10 +429,16 @@ // Location where this function was defined. int location_line; int location_column; + int end_location_line; + int end_location_column; // The name of the parent function, if any. std::string parent_name; + // The list of subfunctions (if any) in the order they appear in the + // file. + std::list subfcn_names; + // The time the file was parsed. octave_time t_parsed; @@ -458,6 +487,8 @@ jit_function_info *jit_info; #endif + void maybe_relocate_end_internal (void); + void print_code_function_header (void); void print_code_function_trailer (void); diff -r 4adf3c4bd80b -r de91b1621260 libinterp/parse-tree/oct-parse.in.yy --- a/libinterp/parse-tree/oct-parse.in.yy Mon May 06 20:02:08 2013 -0400 +++ b/libinterp/parse-tree/oct-parse.in.yy Tue May 07 15:29:00 2013 -0400 @@ -219,14 +219,16 @@ %token METAQUERY %token SUPERCLASSREF %token GET SET +%token FCN // Other tokens. %token END_OF_INPUT LEXICAL_ERROR -%token FCN INPUT_FILE CLASSDEF +%token INPUT_FILE CLASSDEF // %token VARARGIN VARARGOUT // Nonterminals we construct. -%type stash_comment function_beg classdef_beg +%type function_beg +%type stash_comment classdef_beg %type properties_beg methods_beg events_beg enum_beg %type sep_no_nl opt_sep_no_nl nl opt_nl sep opt_sep %type input @@ -1119,9 +1121,9 @@ if (! lexer.reading_fcn_file) { tree_statement *end_of_script - = parser.make_end ("endscript", - lexer.input_line_number, - lexer.current_input_column); + = parser.make_end ("endscript", true, + lexer.input_line_number, + lexer.current_input_column); parser.make_script ($3, end_of_script); } @@ -1134,23 +1136,25 @@ // Function definition // =================== -function_beg : push_fcn_symtab FCN stash_comment +function_beg : push_fcn_symtab FCN { - $$ = $3; + $$ = $2; if (lexer.reading_classdef_file || lexer.parsing_classdef) lexer.maybe_classdef_get_set_method = true; } ; -function : function_beg function1 +function : function_beg stash_comment function1 { - $$ = parser.finish_function (0, $2, $1); + $$ = parser.finish_function (0, $3, $2, $1->line (), + $1->column ()); parser.recover_from_parsing_function (); } - | function_beg return_list '=' function1 + | function_beg stash_comment return_list '=' function1 { - $$ = parser.finish_function ($2, $4, $1); + $$ = parser.finish_function ($3, $5, $2, $1->line (), + $1->column ()); parser.recover_from_parsing_function (); } ; @@ -1199,7 +1203,8 @@ { parser.endfunction_found = true; if (parser.end_token_ok ($1, token::function_end)) - $$ = parser.make_end ("endfunction", $1->line (), $1->column ()); + $$ = parser.make_end ("endfunction", false, + $1->line (), $1->column ()); else ABORT_PARSE; } @@ -1233,9 +1238,9 @@ YYABORT; } - $$ = parser.make_end ("endfunction", - lexer.input_line_number, - lexer.current_input_column); + $$ = parser.make_end ("endfunction", true, + lexer.input_line_number, + lexer.current_input_column); } ; @@ -1255,7 +1260,8 @@ lexer.parsing_classdef = false; if (parser.end_token_ok ($1, token::classdef_end)) - $$ = parser.make_end ("endclassdef", $1->line (), $1->column ()); + $$ = parser.make_end ("endclassdef", false, + $1->line (), $1->column ()); else ABORT_PARSE; } @@ -1494,6 +1500,7 @@ curr_class_name = ""; function_scopes.clear (); primary_fcn_ptr = 0; + subfunction_names.clear (); delete stmt_list; stmt_list = 0; @@ -2598,15 +2605,17 @@ octave_comment_list *tc = octave_comment_buffer::get_comment (); fcn->stash_trailing_comment (tc); + fcn->stash_fcn_end_location (end_fcn_stmt->line (), + end_fcn_stmt->column ()); } return fcn; } tree_statement * -octave_base_parser::make_end (const std::string& type, int l, int c) +octave_base_parser::make_end (const std::string& type, bool eof, int l, int c) { - return make_statement (new tree_no_op_command (type, l, c)); + return make_statement (new tree_no_op_command (type, eof, l, c)); } // Do most of the work for defining a function. @@ -2695,8 +2704,6 @@ } fcn->stash_function_name (id_name); - fcn->stash_fcn_location (lexer.input_line_number, - lexer.current_input_column); if (! lexer.help_text.empty () && curr_fcn_depth == 1 && ! parsing_subfunctions) @@ -2716,7 +2723,8 @@ tree_function_def * octave_base_parser::finish_function (tree_parameter_list *ret_list, octave_user_function *fcn, - octave_comment_list *lc) + octave_comment_list *lc, + int l, int c) { tree_function_def *retval = 0; @@ -2742,6 +2750,9 @@ if (curr_fcn_depth > 1 || parsing_subfunctions) { fcn->mark_as_subfunction (); + fcn->stash_fcn_location (l, c); + + subfunction_names.push_back (nm); if (endfunction_found && function_scopes.size () > 1) { @@ -3301,6 +3312,19 @@ fcn_ptr = parser.primary_fcn_ptr; + if (fcn_ptr) + { + fcn_ptr->maybe_relocate_end (); + + if (parser.parsing_subfunctions) + { + if (! parser.endfunction_found) + parser.subfunction_names.reverse (); + + fcn_ptr->stash_subfunction_names (parser.subfunction_names); + } + } + if (status != 0) error ("parse error while reading file %s", full_file.c_str ()); } diff -r 4adf3c4bd80b -r de91b1621260 libinterp/parse-tree/parse.h --- a/libinterp/parse-tree/parse.h Mon May 06 20:02:08 2013 -0400 +++ b/libinterp/parse-tree/parse.h Tue May 07 15:29:00 2013 -0400 @@ -136,7 +136,7 @@ parsing_subfunctions (false), max_fcn_depth (0), curr_fcn_depth (0), primary_fcn_scope (-1), curr_class_name (), function_scopes (), primary_fcn_ptr (0), - stmt_list (0), + subfunction_names (), stmt_list (0), lexer (lxr) { init (); @@ -270,7 +270,7 @@ tree_statement *end_function); // Create a no-op statement for end_function. - tree_statement *make_end (const std::string& type, int l, int c); + tree_statement *make_end (const std::string& type, bool eof, int l, int c); // Do most of the work for defining a function. octave_user_function * @@ -279,7 +279,8 @@ // Finish defining a function. tree_function_def * finish_function (tree_parameter_list *ret_list, - octave_user_function *fcn, octave_comment_list *lc); + octave_user_function *fcn, octave_comment_list *lc, + int l, int c); // Reset state after parsing function. void @@ -377,6 +378,11 @@ // Pointer to the primary user function or user script function. octave_function *primary_fcn_ptr; + // List of subfunction names, initially in the order they are + // installed in the symbol table, then ordered as they appear in the + // file. Eventually stashed in the primary function object. + std::list subfunction_names; + // Result of parsing input. tree_statement_list *stmt_list; diff -r 4adf3c4bd80b -r de91b1621260 libinterp/parse-tree/pt-cmd.cc --- a/libinterp/parse-tree/pt-cmd.cc Mon May 06 20:02:08 2013 -0400 +++ b/libinterp/parse-tree/pt-cmd.cc Tue May 07 15:29:00 2013 -0400 @@ -33,7 +33,8 @@ tree_no_op_command::dup (symbol_table::scope_id, symbol_table::context_id) const { - return new tree_no_op_command (orig_cmd, line (), column ()); + return new tree_no_op_command (orig_cmd, is_end_of_file (), + line (), column ()); } void diff -r 4adf3c4bd80b -r de91b1621260 libinterp/parse-tree/pt-cmd.h --- a/libinterp/parse-tree/pt-cmd.h Mon May 06 20:02:08 2013 -0400 +++ b/libinterp/parse-tree/pt-cmd.h Tue May 07 15:29:00 2013 -0400 @@ -63,9 +63,9 @@ { public: - tree_no_op_command (const std::string& cmd = "no_op", int l = -1, int c = -1) - : tree_command (l, c), eof (cmd == "endfunction" || cmd == "endscript"), - orig_cmd (cmd) { } + tree_no_op_command (const std::string& cmd = "no_op", bool e = false, + int l = -1, int c = -1) + : tree_command (l, c), eof (e), orig_cmd (cmd) { } ~tree_no_op_command (void) { } @@ -74,7 +74,12 @@ void accept (tree_walker& tw); - bool is_end_of_fcn_or_script (void) const { return eof; } + bool is_end_of_fcn_or_script (void) const + { + return (orig_cmd == "endfunction" || orig_cmd == "endscript"); + } + + bool is_end_of_file (void) const { return eof; } std::string original_command (void) { return orig_cmd; } diff -r 4adf3c4bd80b -r de91b1621260 libinterp/parse-tree/pt-stmt.cc --- a/libinterp/parse-tree/pt-stmt.cc Mon May 06 20:02:08 2013 -0400 +++ b/libinterp/parse-tree/pt-stmt.cc Tue May 07 15:29:00 2013 -0400 @@ -107,6 +107,15 @@ } void +tree_statement::set_location (int l, int c) +{ + if (cmd) + cmd->set_location (l, c); + else if (expr) + expr->set_location (l, c); +} + +void tree_statement::echo_code (void) { tree_print_code tpc (octave_stdout, VPS4); @@ -131,6 +140,23 @@ return retval; } +bool +tree_statement::is_end_of_file (void) const +{ + bool retval = false; + + if (cmd) + { + tree_no_op_command *no_op_cmd + = dynamic_cast (cmd); + + if (no_op_cmd) + retval = no_op_cmd->is_end_of_file (); + } + + return retval; +} + tree_statement * tree_statement::dup (symbol_table::scope_id scope, symbol_table::context_id context) const diff -r 4adf3c4bd80b -r de91b1621260 libinterp/parse-tree/pt-stmt.h --- a/libinterp/parse-tree/pt-stmt.h Mon May 06 20:02:08 2013 -0400 +++ b/libinterp/parse-tree/pt-stmt.h Tue May 07 15:29:00 2013 -0400 @@ -74,6 +74,8 @@ int line (void) const; int column (void) const; + void set_location (int l, int c); + void echo_code (void); tree_command *command (void) { return cmd; } @@ -86,6 +88,8 @@ bool is_end_of_fcn_or_script (void) const; + bool is_end_of_file (void) const; + // Allow modification of this statement. Note that there is no // checking. If you use these, are you sure you knwo what you are // doing? diff -r 4adf3c4bd80b -r de91b1621260 libinterp/parse-tree/pt.h --- a/libinterp/parse-tree/pt.h Mon May 06 20:02:08 2013 -0400 +++ b/libinterp/parse-tree/pt.h Tue May 07 15:29:00 2013 -0400 @@ -50,6 +50,12 @@ void column (int c) { column_num = c; } + void set_location (int l, int c) + { + line_num = l; + column_num = c; + } + virtual void set_breakpoint (void) { bp = true; } virtual void delete_breakpoint (void) { bp = false; } diff -r 4adf3c4bd80b -r de91b1621260 liboctave/util/base-list.h --- a/liboctave/util/base-list.h Mon May 06 20:02:08 2013 -0400 +++ b/liboctave/util/base-list.h Tue May 07 15:29:00 2013 -0400 @@ -36,6 +36,9 @@ typedef typename std::list::iterator iterator; typedef typename std::list::const_iterator const_iterator; + typedef typename std::list::reverse_iterator reverse_iterator; + typedef typename std::list::const_reverse_iterator const_reverse_iterator; + bool empty (void) const { return lst.empty (); } size_t size (void) const { return lst.size (); } @@ -74,6 +77,12 @@ iterator end (void) { return iterator (lst.end ()); } const_iterator end (void) const { return const_iterator (lst.end ()); } + reverse_iterator rbegin (void) { return reverse_iterator (lst.rbegin ()); } + const_reverse_iterator rbegin (void) const { return const_reverse_iterator (lst.rbegin ()); } + + reverse_iterator rend (void) { return reverse_iterator (lst.rend ()); } + const_reverse_iterator rend (void) const { return const_reverse_iterator (lst.rend ()); } + elt_type& front (void) { return lst.front (); } elt_type& back (void) { return lst.back (); }