From owner-bug-octave at bevo dot che dot wisc dot edu Thu Jan 23 10:33:27 1997 Subject: behaviour of the `error' function From: "John W. Eaton" To: Francesco Potorti` Cc: Octave bugs list Date: Thu, 23 Jan 1997 10:31:22 -0600 On 20-Jan-1997, I wrote: : If error() is called inside a function, the function exits immediately : after the error message. If error() is called from a script, the : errors are printed, but the script keeps on going. This is similar to : the way Bourne shell scripts work unless you say `set -e'. I agree : that you should be able to make Octave stop executing the script : immediately after the first error. The PROJECTS file currently has : the following item: : : * Add an option to make Octave quit executing a script when error() is : called. Also make it possible for `return' or `break' to exit a : script. : : but I've not had time to work on this feature yet. After giving this some more thought, I think the current behavior is probably not what is most often wanted. The following patch implements these changes: * Octave now stops executing commands from a script file if an error is encountered. * The return, and break commands now cause Octave to quit executing commands from script files. When used in invalid contexts, the break, continue, and return commands are now simply ignored instead of producing parse errors. Thanks, jwe Thu Jan 23 10:00:00 1997 John W. Eaton * pt-pr-code.h, pt-pr-code.cc (tree_print_code::visit_no_op_command): New function. * pt-cmd.h, pt-cmd.cc (tree_no_op_command): New class. * parse.y (make_break_command, make_continue_command, make_return_command): Where they don't really make sense, turn these commands into no-ops. Accept return and break if reading a script file. * toplev.cc (parse_and_execute): Handle return and break in script files. Quit executing commands if an error occurs when reading a script file. Set global_command to 0 after deleting it. (main_loop): If not interactive or forced_interactive, handle break and return, and quit executing commands if an error occurs. Set global_command to 0 after deleting it. * error.cc (Ferror): Doc fix. * pt-walk.h (tree_walker): Add declaration for visit_no_op_command. Index: toplev.cc =================================================================== RCS file: /home/jwe/src/master/octave/src/toplev.cc,v retrieving revision 1.42 diff -c -r1.42 toplev.cc *** toplev.cc 1997/01/21 03:57:47 1.42 --- toplev.cc 1997/01/23 16:10:12 *************** *** 91,96 **** --- 91,102 ---- // User's home directory. string Vhome_directory; + // Nonzero means we're breaking out of a loop or function body. + extern int breaking; + + // Nonzero means we're returning from a function. + extern int returning; + // Nonzero means we are using readline. // (--no-line-editing) #if defined (USE_READLINE) *************** *** 160,166 **** --- 166,194 ---- if (retval == 0 && global_command) { global_command->eval (print); + delete global_command; + + global_command = 0; + + bool quit = (returning || breaking); + + if (returning) + returning = 0; + + if (breaking) + breaking--; + + if (error_state) + { + error ("near line %d of file `%s'", input_line_number, + curr_fcn_file_full_name.c_str ()); + + break; + } + + if (quit) + break; } } while (retval == 0); *************** *** 254,263 **** delete global_command; ! if (octave_completion_matches_called) ! octave_completion_matches_called = false; else ! current_command_number++; } } while (retval == 0); --- 282,315 ---- delete global_command; ! global_command = 0; ! ! if (! (interactive || forced_interactive)) ! { ! bool quit = (returning || breaking); ! ! if (returning) ! returning = 0; ! ! if (breaking) ! breaking--; ! ! if (quit) ! break; ! } ! ! if (error_state) ! { ! if (! (interactive || forced_interactive)) ! break; ! } else ! { ! if (octave_completion_matches_called) ! octave_completion_matches_called = false; ! else ! current_command_number++; ! } } } while (retval == 0); Index: parse.y =================================================================== RCS file: /home/jwe/src/master/octave/src/parse.y,v retrieving revision 1.97 diff -c -r1.97 parse.y *** parse.y 1996/11/20 02:17:08 1.97 --- parse.y 1997/01/23 15:48:49 *************** *** 1869,1883 **** { tree_command *retval = 0; ! if (! (lexer_flags.looping || lexer_flags.defining_func)) ! yyerror ("break: only meaningful within a loop or function body"); ! else ! { ! int l = break_tok->line (); ! int c = break_tok->column (); ! retval = new tree_break_command (l, c); ! } return retval; } --- 1869,1881 ---- { tree_command *retval = 0; ! int l = break_tok->line (); ! int c = break_tok->column (); ! if (lexer_flags.looping || lexer_flags.defining_func || reading_script_file) ! retval = new tree_break_command (l, c); ! else ! retval = new tree_no_op_command ("break", l, c); return retval; } *************** *** 1889,1903 **** { tree_command *retval = 0; ! if (! lexer_flags.looping) ! yyerror ("continue: only meaningful within a `for' or `while' loop"); ! else ! { ! int l = continue_tok->line (); ! int c = continue_tok->column (); ! retval = new tree_continue_command (l, c); ! } return retval; } --- 1887,1899 ---- { tree_command *retval = 0; ! int l = continue_tok->line (); ! int c = continue_tok->column (); ! if (lexer_flags.looping) ! retval = new tree_continue_command (l, c); ! else ! retval = new tree_no_op_command ("continue", l, c); return retval; } *************** *** 1909,1923 **** { tree_command *retval = 0; ! if (! lexer_flags.defining_func) ! yyerror ("return: only meaningful within a function"); ! else ! { ! int l = return_tok->line (); ! int c = return_tok->column (); ! retval = new tree_return_command (l, c); ! } return retval; } --- 1905,1917 ---- { tree_command *retval = 0; ! int l = return_tok->line (); ! int c = return_tok->column (); ! if (lexer_flags.defining_func || reading_script_file) ! retval = new tree_return_command (l, c); ! else ! retval = new tree_no_op_command ("return", l, c); return retval; } Index: pt-cmd.h =================================================================== RCS file: /home/jwe/src/master/octave/src/pt-cmd.h,v retrieving revision 1.18 diff -c -r1.18 pt-cmd.h *** pt-cmd.h 1996/05/12 07:16:36 1.18 --- pt-cmd.h 1997/01/23 15:53:37 *************** *** 48,59 **** --- 48,62 ---- class tree_if_command; class tree_try_catch_command; class tree_unwind_protect_command; + class tree_no_op_command; class tree_break_command; class tree_continue_command; class tree_return_command; class tree_walker; + #include + #include "pt-base.h" // A base class for commands. *************** *** 288,293 **** --- 291,319 ---- // The code to execute if an error occurs in the first block. tree_statement_list *catch_code; + }; + + // No-op. + + class + tree_no_op_command : public tree_command + { + public: + + tree_no_op_command (const string& cmd = "no_op", int l = -1, int c = -1) + : tree_command (l, c), orig_cmd (cmd) { } + + ~tree_no_op_command (void) { } + + void eval (void) { } + + void accept (tree_walker& tw); + + string original_command (void) { return orig_cmd; } + + private: + + string orig_cmd; }; // Break. Index: pt-cmd.cc =================================================================== RCS file: /home/jwe/src/master/octave/src/pt-cmd.cc,v retrieving revision 1.31 diff -c -r1.31 pt-cmd.cc *** pt-cmd.cc 1996/10/30 19:39:04 1.31 --- pt-cmd.cc 1997/01/23 15:52:10 *************** *** 686,691 **** --- 686,699 ---- tw.visit_unwind_protect_command (*this); } + // No-op. + + void + tree_no_op_command::accept (tree_walker& tw) + { + tw.visit_no_op_command (*this); + } + // Break. void Index: pt-pr-code.h =================================================================== RCS file: /home/jwe/src/master/octave/src/pt-pr-code.h,v retrieving revision 1.3 diff -c -r1.3 pt-pr-code.h *** pt-pr-code.h 1996/11/19 18:06:02 1.3 --- pt-pr-code.h 1997/01/23 15:57:10 *************** *** 88,93 **** --- 88,95 ---- void visit_multi_assignment_expression (tree_multi_assignment_expression&); + void visit_no_op_command (tree_no_op_command&); + void visit_oct_obj (tree_oct_obj&); void visit_constant (tree_constant&); Index: pt-pr-code.cc =================================================================== RCS file: /home/jwe/src/master/octave/src/pt-pr-code.cc,v retrieving revision 1.7 diff -c -r1.7 pt-pr-code.cc *** pt-pr-code.cc 1996/11/19 18:06:02 1.7 --- pt-pr-code.cc 1997/01/23 15:40:29 *************** *** 553,558 **** --- 553,566 ---- } void + tree_print_code::visit_no_op_command (tree_no_op_command& cmd) + { + indent (); + + os << cmd.original_command (); + } + + void tree_print_code::visit_oct_obj (tree_oct_obj&) { ::error ("visit_oct_obj: internal error"); Index: pt-walk.h =================================================================== RCS file: /home/jwe/src/master/octave/src/pt-walk.h,v retrieving revision 1.2 diff -c -r1.2 pt-walk.h *** pt-walk.h 1996/10/12 00:15:08 1.2 --- pt-walk.h 1997/01/23 15:38:18 *************** *** 99,104 **** --- 99,107 ---- visit_multi_assignment_expression (tree_multi_assignment_expression&) = 0; virtual void + visit_no_op_command (tree_no_op_command&) = 0; + + virtual void visit_oct_obj (tree_oct_obj&) = 0; virtual void Index: error.cc =================================================================== RCS file: /home/jwe/src/master/octave/src/error.cc,v retrieving revision 1.51 diff -c -r1.51 error.cc *** error.cc 1996/10/11 23:51:15 1.51 --- error.cc 1997/01/23 06:39:00 *************** *** 252,259 **** This should eventually take us up to the top level, possibly\n\ printing traceback messages as we go.\n\ \n\ ! If MESSAGE ends in a newline character, traceback messages are not\n\ ! printed.\n\ \n\ See also: printf") { --- 252,259 ---- This should eventually take us up to the top level, possibly\n\ printing traceback messages as we go.\n\ \n\ ! If the resulting error message ends in a newline character, traceback ! messages are not printed.\n\ \n\ See also: printf") {