Mercurial > hg > octave-lyh
changeset 16627:de91b1621260
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.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Tue, 07 May 2013 15:29:00 -0400 |
parents | 4adf3c4bd80b |
children | a66c285729a6 |
files | libinterp/interpfcn/debug.cc libinterp/interpfcn/debug.h libinterp/octave-value/ov-fcn.h libinterp/octave-value/ov-usr-fcn.cc libinterp/octave-value/ov-usr-fcn.h libinterp/parse-tree/oct-parse.in.yy libinterp/parse-tree/parse.h libinterp/parse-tree/pt-cmd.cc libinterp/parse-tree/pt-cmd.h libinterp/parse-tree/pt-stmt.cc libinterp/parse-tree/pt-stmt.h libinterp/parse-tree/pt.h liboctave/util/base-list.h |
diffstat | 13 files changed, 351 insertions(+), 71 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/interpfcn/debug.cc +++ b/libinterp/interpfcn/debug.cc @@ -316,19 +316,27 @@ { if (! do_add_breakpoint_1 (dbg_fcn, fname, line, retval)) { - typedef std::map<std::string, octave_value>::const_iterator - subfunction_map_const_iterator; + // Search subfunctions in the order they appear in the file. + + const std::list<std::string> subfcn_names + = dbg_fcn->subfunction_names (); std::map<std::string, octave_value> subfcns = dbg_fcn->subfunctions (); - for (subfunction_map_const_iterator p = subfcns.begin (); - p != subfcns.end (); p++) + for (std::list<std::string>::const_iterator p = subfcn_names.begin (); + p != subfcn_names.end (); p++) { - octave_user_code *dbg_subfcn = p->second.user_code_value (); + std::map<std::string, octave_value>::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<std::string> 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<std::string, octave_value> subfcns + = dbg_fcn->subfunctions (); - if (p != line.end ()) - { - int lineno = p->second; - - cmds->delete_breakpoint (lineno); + for (std::list<std::string>::const_iterator p = subfcn_names.begin (); + p != subfcn_names.end (); p++) + { + std::map<std::string, octave_value>::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<std::string, octave_value>::const_iterator + subfcns_const_iterator; - if (cmds) + std::map<std::string, octave_value> 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)
--- a/libinterp/interpfcn/debug.h +++ b/libinterp/interpfcn/debug.h @@ -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);
--- a/libinterp/octave-value/ov-fcn.h +++ b/libinterp/octave-value/ov-fcn.h @@ -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<std::string>&) { } + + virtual std::list<std::string> subfunction_names (void) const + { + return std::list<std::string> (); + } + void mark_relative (void) { relative = true; } bool is_relative (void) const { return relative; }
--- a/libinterp/octave-value/ov-usr-fcn.cc +++ b/libinterp/octave-value/ov-usr-fcn.cc @@ -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<std::string, octave_value> fcns = subfunctions (); + + if (! fcns.empty ()) + { + for (std::map<std::string, octave_value>::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<std::string>& names) +{ + subfcn_names = names; +} + octave_value_list octave_user_function::all_va_args (const octave_value_list& args) {
--- a/libinterp/octave-value/ov-usr-fcn.h +++ b/libinterp/octave-value/ov-usr-fcn.h @@ -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<std::string, octave_value> subfunctions (void) const; + bool has_subfunctions (void) const; + + void stash_subfunction_names (const std::list<std::string>& names); + + std::list<std::string> 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<std::string> 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);
--- a/libinterp/parse-tree/oct-parse.in.yy +++ b/libinterp/parse-tree/oct-parse.in.yy @@ -219,14 +219,16 @@ %token <tok_val> METAQUERY %token <tok_val> SUPERCLASSREF %token <tok_val> GET SET +%token <tok_val> 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 <comment_type> stash_comment function_beg classdef_beg +%type <tok_val> function_beg +%type <comment_type> stash_comment classdef_beg %type <comment_type> properties_beg methods_beg events_beg enum_beg %type <sep_type> sep_no_nl opt_sep_no_nl nl opt_nl sep opt_sep %type <tree_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 ()); }
--- a/libinterp/parse-tree/parse.h +++ b/libinterp/parse-tree/parse.h @@ -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<std::string> subfunction_names; + // Result of parsing input. tree_statement_list *stmt_list;
--- a/libinterp/parse-tree/pt-cmd.cc +++ b/libinterp/parse-tree/pt-cmd.cc @@ -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
--- a/libinterp/parse-tree/pt-cmd.h +++ b/libinterp/parse-tree/pt-cmd.h @@ -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; }
--- a/libinterp/parse-tree/pt-stmt.cc +++ b/libinterp/parse-tree/pt-stmt.cc @@ -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<tree_no_op_command *> (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
--- a/libinterp/parse-tree/pt-stmt.h +++ b/libinterp/parse-tree/pt-stmt.h @@ -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?
--- a/libinterp/parse-tree/pt.h +++ b/libinterp/parse-tree/pt.h @@ -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; }
--- a/liboctave/util/base-list.h +++ b/liboctave/util/base-list.h @@ -36,6 +36,9 @@ typedef typename std::list<elt_type>::iterator iterator; typedef typename std::list<elt_type>::const_iterator const_iterator; + typedef typename std::list<elt_type>::reverse_iterator reverse_iterator; + typedef typename std::list<elt_type>::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 (); }