Mercurial > octave
changeset 23723:ab8831d346c1
revamp echo command and move related variables inside tree_evaluator class
* pt-stmt.h, pt-stmt.cc (tree_statement::echo_code): New argument,
prefix. Pass prefix to tree_print_code constructor instead of VPS4.
* basics.txi: Delete documentation for echo_executing_commands.
* interpreter.h, interpreter.cc (interpreter::maximum_braindamage):
Now a member function.
(interpreter::interpreter): Call tree_evaluator::echo directly instead
of using Fecho_executing_commands. Don't force input to be echoed if
forced_interactive is etst.
* input.h, input.cc (Fecho_executing_commands): Delete.
(Vecho_executing_commands): Delete variable and all uses.
(VPS4): Delete.
(set_default_prompts): Don't set global value for PS4 here.
(base_reader::do_input_echo): Delete.
(gnu_readline): Don't call do_input_echo.
* pt-eval.h, pt-eval.cc (Fecho_executing_commands): Delete.
(FPS4): Move here from input.cc.
(Fecho): Move here from input.cc Rewrite. Handle "echo function
on|off" syntax.
(echo_state): Move enum declaration to tree_evaluator class from input.h.
* ov-usr-fcn.cc (octave_user_script::call, octave_user_function::call):
Push echo state before executing commands. Don't print function
header or trailer here.
(octave_user_function::print_code_function_header,
octave_user_function::print_code_function_trailer): New arg, prefix.
Pass prefix to tree_print_code constructor instead of VPS4.
* pt-eval.h, pt-eval.cc (tree_evaluator::m_PS4,
tree_evaluator::m_echo, tree_evaluator::m_echo_state,
tree_evaluator::m_echo_file_name, tree_evaluator::m_echo_file_pos,
tree_evaluator::m_echo_files): New member variables.
(tree_evaluator::echo_state, tree_evaluator::PS4,
tree_evaluator::echo, tree_evaluator::push_echo_state,
tree_evaluator::set_echo_state, tree_evaluator::set_echo_file_name,
tree_evaluator::set_echo_file_pos, tree_evaluator::echo_this_file,
tree_evaluator::echo_code): New member functions.
(tree_evaluator::visit_break_command,
tree_evaluator::visit_continue_command,
tree_evaluator::visit_decl_command,
tree_evaluator::visit_simple_for_command,
tree_evaluator::visit_complex_for_command,
tree_evaluator::visit_if_command,
tree_evaluator::visit_no_op_command,
tree_evaluator::visit_return_command,
tree_evaluator::visit_switch_command,
tree_evaluator::visit_try_catch_command,
tree_evaluator::visit_unwind_protect_command,
tree_evaluator::visit_while_command,
tree_evaluator::visit_do_until_command):
Manage echo_file_pos and echo code here.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Fri, 30 Jun 2017 20:59:54 -0400 |
parents | ab9e51f41a29 |
children | 517078d102ff |
files | doc/interpreter/basics.txi libinterp/corefcn/input.cc libinterp/corefcn/input.h libinterp/corefcn/interpreter.cc libinterp/corefcn/interpreter.h libinterp/corefcn/oct-hist.cc libinterp/octave-value/ov-usr-fcn.cc libinterp/octave-value/ov-usr-fcn.h libinterp/parse-tree/pt-eval.cc libinterp/parse-tree/pt-eval.h libinterp/parse-tree/pt-stmt.cc libinterp/parse-tree/pt-stmt.h |
diffstat | 12 files changed, 533 insertions(+), 327 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/interpreter/basics.txi Fri Jun 30 01:21:31 2017 -0400 +++ b/doc/interpreter/basics.txi Fri Jun 30 20:59:54 2017 -0400 @@ -846,8 +846,6 @@ @DOCSTRING(echo) -@DOCSTRING(echo_executing_commands) - @node Errors @section How Octave Reports Errors @cindex error messages
--- a/libinterp/corefcn/input.cc Fri Jun 30 01:21:31 2017 -0400 +++ b/libinterp/corefcn/input.cc Fri Jun 30 20:59:54 2017 -0400 @@ -81,18 +81,6 @@ // Secondary prompt string. static std::string VPS2; -// String printed before echoed input (enabled by --echo-input). -std::string VPS4 = "+ "; - -// Echo commands as they are executed? -// -// 1 ==> echo commands read from script files -// 2 ==> echo commands from functions -// 4 ==> echo commands read from command line -// -// more than one state can be active at once. -int Vecho_executing_commands = ECHO_OFF; - // The time we last printed a prompt. octave::sys::time Vlast_prompt_time = 0.0; @@ -141,45 +129,11 @@ VPS1 = "octave:\\#> "; VPS2 = "> "; - VPS4 = "+ "; + std::string VPS4 = "+ "; octave_link::set_default_prompts (VPS1, VPS2, VPS4); } -namespace octave -{ - void - base_reader::do_input_echo (const std::string& input_string) const - { - bool forced_interactive = application::forced_interactive (); - - int do_echo = reading_script_file () - ? (Vecho_executing_commands & ECHO_SCRIPTS) - : ((Vecho_executing_commands & ECHO_CMD_LINE) && ! forced_interactive); - - if (do_echo) - { - if (forced_interactive) - { - if (pflag > 0) - octave_stdout << command_editor::decode_prompt_string (VPS1); - else - octave_stdout << command_editor::decode_prompt_string (VPS2); - } - else - octave_stdout << command_editor::decode_prompt_string (VPS4); - - if (! input_string.empty ()) - { - octave_stdout << input_string; - - if (input_string[input_string.length () - 1] != '\n') - octave_stdout << "\n"; - } - } - } -} - static std::string gnu_readline (const std::string& s, bool& eof) { @@ -308,8 +262,6 @@ if (retval[retval.length () - 1] != '\n') octave_diary << "\n"; - - do_input_echo (retval); } else octave_diary << "\n"; @@ -1025,137 +977,6 @@ return ovl (); } -DEFUN (echo, args, , - doc: /* -*- texinfo -*- -@deftypefn {} {} echo -@deftypefnx {} {} echo on -@deftypefnx {} {} echo off -@deftypefnx {} {} echo on all -@deftypefnx {} {} echo off all -Control whether commands are displayed as they are executed. - -Valid options are: - -@table @code -@item on -Enable echoing of commands as they are executed in script files. - -@item off -Disable echoing of commands as they are executed in script files. - -@item on all -Enable echoing of commands as they are executed in script files and -functions. - -@item off all -Disable echoing of commands as they are executed in script files and -functions. -@end table - -@noindent -With no arguments, @code{echo} toggles the current echo state. - -@seealso{echo_executing_commands} -@end deftypefn */) -{ - string_vector argv = args.make_argv (); - - switch (args.length ()) - { - case 0: - { - if ((Vecho_executing_commands & ECHO_SCRIPTS) - || (Vecho_executing_commands & ECHO_FUNCTIONS)) - Vecho_executing_commands = ECHO_OFF; - else - Vecho_executing_commands = ECHO_SCRIPTS; - } - break; - - case 1: - { - std::string arg = argv[0]; - - if (arg == "on") - Vecho_executing_commands = ECHO_SCRIPTS; - else if (arg == "off") - Vecho_executing_commands = ECHO_OFF; - else - print_usage (); - } - break; - - case 2: - { - std::string arg = argv[0]; - - if (arg == "on" && argv[1] == "all") - { - int tmp = (ECHO_SCRIPTS | ECHO_FUNCTIONS); - Vecho_executing_commands = tmp; - } - else if (arg == "off" && argv[1] == "all") - Vecho_executing_commands = ECHO_OFF; - else - print_usage (); - } - break; - - default: - print_usage (); - break; - } - - return ovl (); -} - -/* -%!test -%! state = echo_executing_commands (); -%! unwind_protect -%! echo (); -%! s1 = echo_executing_commands (); -%! assert (s1 != state); -%! echo (); -%! s2 = echo_executing_commands (); -%! assert (s2 != s1); -%! unwind_protect_cleanup -%! echo_executing_commands (state); -%! end_unwind_protect - -%!test -%! state = echo_executing_commands (); -%! unwind_protect -%! echo ("off"); -%! assert (echo_executing_commands () == 0); -%! echo ("on"); -%! assert (echo_executing_commands () != 0); -%! echo ("off"); -%! assert (echo_executing_commands () == 0); -%! unwind_protect_cleanup -%! echo_executing_commands (state); -%! end_unwind_protect - -%!#test # FIXME: This passes, but produces a lot of onscreen output -%! state = echo_executing_commands (); -%! unwind_protect -%! echo ("on", "all"); -%! assert (echo_executing_commands () != 0); -%! echo ("off", "all"); -%! assert (echo_executing_commands () == 0); -%! unwind_protect_cleanup -%! echo_executing_commands (state); -%! end_unwind_protect - -%!error echo ([]) -%!error echo (0) -%!error echo ("") -%!error echo ("Octave") -%!error echo ("off", "invalid") -%!error echo ("on", "invalid") -%!error echo ("on", "all", "all") -*/ - DEFUN (completion_matches, args, nargout, doc: /* -*- texinfo -*- @deftypefn {} {} completion_matches (@var{hint}) @@ -1437,26 +1258,6 @@ return SET_INTERNAL_VARIABLE (PS2); } -DEFUN (PS4, args, nargout, - doc: /* -*- texinfo -*- -@deftypefn {} {@var{val} =} PS4 () -@deftypefnx {} {@var{old_val} =} PS4 (@var{new_val}) -@deftypefnx {} {} PS4 (@var{new_val}, "local") -Query or set the character string used to prefix output produced -when echoing commands is enabled. - -The default value is @qcode{"+ "}. -@xref{Diary and Echo Commands}, for a description of echoing commands. - -When called from inside a function with the @qcode{"local"} option, the -variable is changed locally for the function and any subroutines it calls. -The original variable value is restored when exiting the function. -@seealso{echo, echo_executing_commands, PS1, PS2} -@end deftypefn */) -{ - return SET_INTERNAL_VARIABLE (PS4); -} - DEFUN (completion_append_char, args, nargout, doc: /* -*- texinfo -*- @deftypefn {} {@var{val} =} completion_append_char () @@ -1475,42 +1276,6 @@ return SET_INTERNAL_VARIABLE (completion_append_char); } -DEFUN (echo_executing_commands, args, nargout, - doc: /* -*- texinfo -*- -@deftypefn {} {@var{val} =} echo_executing_commands () -@deftypefnx {} {@var{old_val} =} echo_executing_commands (@var{new_val}) -@deftypefnx {} {} echo_executing_commands (@var{new_val}, "local") -Query or set the internal variable that controls the echo state. - -It may be the sum of the following values: - -@table @asis -@item 1 -Echo commands read from script files. - -@item 2 -Echo commands from functions. - -@item 4 -Echo commands read from command line. -@end table - -More than one state can be active at once. For example, a value of 3 is -equivalent to the command @kbd{echo on all}. - -The value of @code{echo_executing_commands} may be set by the @kbd{echo} -command or the command line option @option{--echo-commands}. - -When called from inside a function with the @qcode{"local"} option, the -variable is changed locally for the function and any subroutines it calls. -The original variable value is restored when exiting the function. - -@seealso{echo} -@end deftypefn */) -{ - return SET_INTERNAL_VARIABLE (echo_executing_commands); -} - DEFUN (__request_drawnow__, args, , doc: /* -*- texinfo -*- @deftypefn {} {} __request_drawnow__ ()
--- a/libinterp/corefcn/input.h Fri Jun 30 01:21:31 2017 -0400 +++ b/libinterp/corefcn/input.h Fri Jun 30 20:59:54 2017 -0400 @@ -70,20 +70,8 @@ extern void set_default_prompts (void); -extern std::string VPS4; - extern char Vfilemarker; -enum echo_state -{ - ECHO_OFF = 0, - ECHO_SCRIPTS = 1, - ECHO_FUNCTIONS = 2, - ECHO_CMD_LINE = 4 -}; - -extern int Vecho_executing_commands; - extern octave::sys::time Vlast_prompt_time; namespace octave @@ -146,8 +134,6 @@ base_lexer *lexer; - void do_input_echo (const std::string&) const; - static const std::string in_src; };
--- a/libinterp/corefcn/interpreter.cc Fri Jun 30 01:21:31 2017 -0400 +++ b/libinterp/corefcn/interpreter.cc Fri Jun 30 20:59:54 2017 -0400 @@ -173,33 +173,6 @@ set_liboctave_warning_with_id_handler (warning_with_id); } -// What internal options get configured by --traditional. - -static void -maximum_braindamage (void) -{ - FPS1 (octave_value (">> ")); - FPS2 (octave_value ("")); - FPS4 (octave_value ("")); - Fbeep_on_error (octave_value (true)); - Fconfirm_recursive_rmdir (octave_value (false)); - Fcrash_dumps_octave_core (octave_value (false)); - Fdisable_diagonal_matrix (octave_value (true)); - Fdisable_permutation_matrix (octave_value (true)); - Fdisable_range (octave_value (true)); - Ffixed_point_format (octave_value (true)); - Fhistory_timestamp_format_string (octave_value ("%%-- %D %I:%M %p --%%")); - Fpage_screen_output (octave_value (false)); - Fprint_empty_dimensions (octave_value (false)); - Fsave_default_options (octave_value ("-mat-binary")); - Fstruct_levels_to_print (octave_value (0)); - - disable_warning ("Octave:abbreviated-property-match"); - disable_warning ("Octave:data-file-in-path"); - disable_warning ("Octave:function-name-clash"); - disable_warning ("Octave:possible-matlab-short-circuit-operator"); -} - DEFUN (quit, args, , doc: /* -*- texinfo -*- @deftypefn {} {} exit @@ -505,10 +478,8 @@ // instead of using the interpreter-level functions. if (options.echo_commands ()) - { - int val = ECHO_SCRIPTS | ECHO_FUNCTIONS | ECHO_CMD_LINE; - Fecho_executing_commands (octave_value (val)); - } + m_evaluator.echo + (tree_evaluator::ECHO_SCRIPTS | tree_evaluator::ECHO_FUNCTIONS); std::string docstrings_file = options.docstrings_file (); if (! docstrings_file.empty ()) @@ -700,16 +671,8 @@ return exit_status; } - // Force input to be echoed if not really interactive, - // but the user has forced interactive behavior. - if (options.forced_interactive ()) - { - command_editor::blink_matching_paren (false); - - // FIXME: is this the right thing to do? - Fecho_executing_commands (octave_value (ECHO_CMD_LINE)); - } + command_editor::blink_matching_paren (false); } // Avoid counting commands executed from startup or script files. @@ -1310,4 +1273,32 @@ return found; } + + // What internal options get configured by --traditional. + + void interpreter::maximum_braindamage (void) + { + FPS1 (octave_value (">> ")); + FPS2 (octave_value ("")); + + m_evaluator.PS4 (""); + + Fbeep_on_error (octave_value (true)); + Fconfirm_recursive_rmdir (octave_value (false)); + Fcrash_dumps_octave_core (octave_value (false)); + Fdisable_diagonal_matrix (octave_value (true)); + Fdisable_permutation_matrix (octave_value (true)); + Fdisable_range (octave_value (true)); + Ffixed_point_format (octave_value (true)); + Fhistory_timestamp_format_string (octave_value ("%%-- %D %I:%M %p --%%")); + Fpage_screen_output (octave_value (false)); + Fprint_empty_dimensions (octave_value (false)); + Fsave_default_options (octave_value ("-mat-binary")); + Fstruct_levels_to_print (octave_value (0)); + + disable_warning ("Octave:abbreviated-property-match"); + disable_warning ("Octave:data-file-in-path"); + disable_warning ("Octave:function-name-clash"); + disable_warning ("Octave:possible-matlab-short-circuit-operator"); + } }
--- a/libinterp/corefcn/interpreter.h Fri Jun 30 01:21:31 2017 -0400 +++ b/libinterp/corefcn/interpreter.h Fri Jun 30 20:59:54 2017 -0400 @@ -242,6 +242,8 @@ bool m_history_initialized; bool m_initialized; + + void maximum_braindamage (void); }; }
--- a/libinterp/corefcn/oct-hist.cc Fri Jun 30 01:21:31 2017 -0400 +++ b/libinterp/corefcn/oct-hist.cc Fri Jun 30 20:59:54 2017 -0400 @@ -492,18 +492,17 @@ file.close (); - // Turn on command echo, so the output from this will make better - // sense. - octave::unwind_protect frame; frame.add_fcn (unlink_cleanup, name.c_str ()); - frame.protect_var (Vecho_executing_commands); frame.protect_var (input_from_tmp_history_file); - Vecho_executing_commands = ECHO_CMD_LINE; input_from_tmp_history_file = true; + // FIXME: instead of sourcing a file, we should just iterate through + // the list of commands, parsing and executing them one at a time as + // if they were entered interactively. + octave::source_file (name); } @@ -515,17 +514,17 @@ if (name.empty ()) return; - // Turn on command echo so the output from this will make better sense. - octave::unwind_protect frame; frame.add_fcn (unlink_cleanup, name.c_str ()); - frame.protect_var (Vecho_executing_commands); frame.protect_var (input_from_tmp_history_file); - Vecho_executing_commands = ECHO_CMD_LINE; input_from_tmp_history_file = true; + // FIXME: instead of sourcing a file, we should just iterate through + // the list of commands, parsing and executing them one at a time as + // if they were entered interactively. + octave::source_file (name); } @@ -587,6 +586,8 @@ @seealso{run_history, history} @end deftypefn */) { + // FIXME: should this be limited to the top-level context? + if (args.length () > 2) print_usage (); @@ -637,6 +638,8 @@ @seealso{edit_history, run_history} @end deftypefn */) { + // FIXME: should this be limited to the top-level context? + // Call do_history even if nargout is zero to display history list. string_vector hlist = do_history (args, nargout); @@ -696,6 +699,8 @@ @seealso{edit_history, history} @end deftypefn */) { + // FIXME: should this be limited to the top-level context? + if (args.length () > 2) print_usage ();
--- a/libinterp/octave-value/ov-usr-fcn.cc Fri Jun 30 01:21:31 2017 -0400 +++ b/libinterp/octave-value/ov-usr-fcn.cc Fri Jun 30 20:59:54 2017 -0400 @@ -145,6 +145,10 @@ profile_data_accumulator::enter<octave_user_script> block (profiler, *this); + if (tw.echo ()) + tw.push_echo_state (frame, octave::tree_evaluator::ECHO_SCRIPTS, + file_name); + cmd_list->accept (tw); if (octave::tree_return_command::returning) @@ -548,11 +552,6 @@ frame.add_method (this, &octave_user_function::restore_warning_states); - bool echo_commands = (Vecho_executing_commands & ECHO_FUNCTIONS); - - if (echo_commands) - print_code_function_header (); - // Evaluate the commands that make up the function. frame.protect_var (octave::tree_evaluator::statement_context); @@ -562,6 +561,10 @@ profile_data_accumulator::enter<octave_user_function> block (profiler, *this); + if (tw.echo ()) + tw.push_echo_state (frame, octave::tree_evaluator::ECHO_FUNCTIONS, + file_name); + if (is_special_expr ()) { assert (cmd_list->length () == 1); @@ -581,9 +584,6 @@ cmd_list->accept (tw); } - if (echo_commands) - print_code_function_trailer (); - if (octave::tree_return_command::returning) octave::tree_return_command::returning = 0; @@ -701,17 +701,17 @@ } void -octave_user_function::print_code_function_header (void) +octave_user_function::print_code_function_header (const std::string& prefix) { - octave::tree_print_code tpc (octave_stdout, VPS4); + octave::tree_print_code tpc (octave_stdout, prefix); tpc.visit_octave_user_function_header (*this); } void -octave_user_function::print_code_function_trailer (void) +octave_user_function::print_code_function_trailer (const std::string& prefix) { - octave::tree_print_code tpc (octave_stdout, VPS4); + octave::tree_print_code tpc (octave_stdout, prefix); tpc.visit_octave_user_function_trailer (*this); }
--- a/libinterp/octave-value/ov-usr-fcn.h Fri Jun 30 01:21:31 2017 -0400 +++ b/libinterp/octave-value/ov-usr-fcn.h Fri Jun 30 20:59:54 2017 -0400 @@ -473,9 +473,9 @@ void maybe_relocate_end_internal (void); - void print_code_function_header (void); + void print_code_function_header (const std::string& prefix); - void print_code_function_trailer (void); + void print_code_function_trailer (const std::string& prefix); void bind_automatic_vars (octave::tree_evaluator& tw, const string_vector& arg_names,
--- a/libinterp/parse-tree/pt-eval.cc Fri Jun 30 01:21:31 2017 -0400 +++ b/libinterp/parse-tree/pt-eval.cc Fri Jun 30 20:59:54 2017 -0400 @@ -31,6 +31,9 @@ #include <fstream> #include <typeinfo> +#include "cmd-edit.h" +#include "oct-env.h" + #include "bp-table.h" #include "call-stack.h" #include "defun.h" @@ -49,6 +52,7 @@ #include "pt-tm-const.h" #include "symtab.h" #include "unwind-prot.h" +#include "utils.h" #include "variables.h" //FIXME: This should be part of tree_evaluator @@ -319,6 +323,13 @@ void tree_evaluator::visit_break_command (tree_break_command& cmd) { + if (m_echo_state) + { + size_t line = cmd.line (); + echo_code (line); + m_echo_file_pos = line + 1; + } + if (debug_mode) do_breakpoint (cmd.is_breakpoint (true)); @@ -394,6 +405,13 @@ void tree_evaluator::visit_continue_command (tree_continue_command& cmd) { + if (m_echo_state) + { + size_t line = cmd.line (); + echo_code (line); + m_echo_file_pos = line + 1; + } + if (debug_mode) do_breakpoint (cmd.is_breakpoint (true)); @@ -661,6 +679,13 @@ void tree_evaluator::visit_decl_command (tree_decl_command& cmd) { + if (m_echo_state) + { + size_t line = cmd.line (); + echo_code (line); + m_echo_file_pos = line + 1; + } + if (debug_mode) do_breakpoint (cmd.is_breakpoint (true)); @@ -736,6 +761,14 @@ void tree_evaluator::visit_simple_for_command (tree_simple_for_command& cmd) { + size_t line = cmd.line (); + + if (m_echo_state) + { + echo_code (line); + line++; + } + if (debug_mode) do_breakpoint (cmd.is_breakpoint (true)); @@ -774,6 +807,9 @@ for (octave_idx_type i = 0; i < steps; i++) { + if (m_echo_state) + m_echo_file_pos = line; + octave_value val (rng.elem (i)); ult.assign (octave_value::op_asn_eq, val); @@ -787,6 +823,9 @@ } else if (rhs.is_scalar_type ()) { + if (m_echo_state) + m_echo_file_pos = line; + ult.assign (octave_value::op_asn_eq, rhs); if (loop_body) @@ -830,6 +869,9 @@ for (octave_idx_type i = 1; i <= steps; i++) { + if (m_echo_state) + m_echo_file_pos = line; + // do_index_op expects one-based indices. idx(iidx) = i; octave_value val = arg.do_index_op (idx); @@ -857,6 +899,14 @@ void tree_evaluator::visit_complex_for_command (tree_complex_for_command& cmd) { + size_t line = cmd.line (); + + if (m_echo_state) + { + echo_code (line); + line++; + } + if (debug_mode) do_breakpoint (cmd.is_breakpoint (true)); @@ -902,6 +952,9 @@ for (octave_idx_type i = 0; i < nel; i++) { + if (m_echo_state) + m_echo_file_pos = line; + std::string key = keys[i]; const Cell val_lst = tmp_val.contents (key); @@ -1036,6 +1089,13 @@ void tree_evaluator::visit_if_command (tree_if_command& cmd) { + if (m_echo_state) + { + size_t line = cmd.line (); + echo_code (line); + m_echo_file_pos = line + 1; + } + tree_if_command_list *lst = cmd.cmd_list (); if (lst) @@ -1822,6 +1882,13 @@ void tree_evaluator::visit_no_op_command (tree_no_op_command& cmd) { + if (m_echo_state) + { + size_t line = cmd.line (); + echo_code (line); + m_echo_file_pos = line + 1; + } + if (debug_mode && cmd.is_end_of_fcn_or_script ()) do_breakpoint (cmd.is_breakpoint (true), true); } @@ -1971,6 +2038,13 @@ void tree_evaluator::visit_return_command (tree_return_command& cmd) { + if (m_echo_state) + { + size_t line = cmd.line (); + echo_code (line); + m_echo_file_pos = line + 1; + } + if (debug_mode) do_breakpoint (cmd.is_breakpoint (true)); @@ -2088,14 +2162,6 @@ if (Vtrack_line_num) m_call_stack.set_location (stmt.line (), stmt.column ()); - - if ((statement_context == script - && ((Vecho_executing_commands & ECHO_SCRIPTS - && m_call_stack.all_scripts ()) - || Vecho_executing_commands & ECHO_FUNCTIONS)) - || (statement_context == function - && Vecho_executing_commands & ECHO_FUNCTIONS)) - stmt.echo_code (); } try @@ -2104,6 +2170,13 @@ cmd->accept (*this); else { + if (m_echo_state) + { + size_t line = stmt.line (); + echo_code (line); + m_echo_file_pos = line + 1; + } + if (debug_mode) do_breakpoint (expr->is_breakpoint (true)); @@ -2216,6 +2289,13 @@ void tree_evaluator::visit_switch_command (tree_switch_command& cmd) { + if (m_echo_state) + { + size_t line = cmd.line (); + echo_code (line); + m_echo_file_pos = line + 1; + } + if (debug_mode) do_breakpoint (cmd.is_breakpoint (true)); @@ -2249,6 +2329,13 @@ void tree_evaluator::visit_try_catch_command (tree_try_catch_command& cmd) { + if (m_echo_state) + { + size_t line = cmd.line (); + echo_code (line); + m_echo_file_pos = line + 1; + } + bool execution_error = false; { @@ -2399,6 +2486,13 @@ void tree_evaluator::visit_unwind_protect_command (tree_unwind_protect_command& cmd) { + if (m_echo_state) + { + size_t line = cmd.line (); + echo_code (line); + m_echo_file_pos = line + 1; + } + tree_statement_list *cleanup_code = cmd.cleanup (); tree_statement_list *unwind_protect_code = cmd.body (); @@ -2442,6 +2536,14 @@ void tree_evaluator::visit_while_command (tree_while_command& cmd) { + size_t line = cmd.line (); + + if (m_echo_state) + { + echo_code (line); + line++; + } + #if defined (HAVE_LLVM) if (tree_jit::execute (cmd)) return; @@ -2460,6 +2562,9 @@ for (;;) { + if (m_echo_state) + m_echo_file_pos = line; + if (debug_mode) do_breakpoint (cmd.is_breakpoint (true)); @@ -2481,6 +2586,14 @@ void tree_evaluator::visit_do_until_command (tree_do_until_command& cmd) { + size_t line = cmd.line (); + + if (m_echo_state) + { + echo_code (line); + line++; + } + #if defined (HAVE_LLVM) if (tree_jit::execute (cmd)) return; @@ -2501,6 +2614,9 @@ for (;;) { + if (m_echo_state) + m_echo_file_pos = line; + tree_statement_list *loop_body = cmd.body (); if (loop_body) @@ -2727,12 +2843,201 @@ "silent_functions"); } + void + tree_evaluator::push_echo_state (unwind_protect& frame, int type, + const std::string& file_name) + { + frame.add_method (*this, &tree_evaluator::set_echo_state, + m_echo_state); + + frame.add_method (*this, &tree_evaluator::set_echo_file_name, + m_echo_file_name); + + frame.add_method (*this, &tree_evaluator::set_echo_file_pos, + m_echo_file_pos); + + m_echo_state = echo_this_file (file_name, type); + m_echo_file_name = file_name; + m_echo_file_pos = 1; + } + octave_value tree_evaluator::string_fill_char (const octave_value_list& args, int nargout) { return set_internal_variable (m_string_fill_char, args, nargout, "string_fill_char"); } + + octave_value + tree_evaluator::echo (const octave_value_list& args, int) + { + string_vector argv = args.make_argv (); + + switch (args.length ()) + { + case 0: + if ((m_echo & ECHO_SCRIPTS) || (m_echo & ECHO_FUNCTIONS)) + { + m_echo = ECHO_OFF; + m_echo_files.clear (); + } + else + m_echo = ECHO_SCRIPTS; + break; + + case 1: + { + std::string arg0 = argv[0]; + + if (arg0 == "on") + m_echo = ECHO_SCRIPTS; + else if (arg0 == "off") + m_echo = ECHO_OFF; + else + { + std::string file = fcn_file_in_path (arg0); + file = sys::env::make_absolute (file); + + if (file.empty ()) + error ("echo: no such file %s", arg0.c_str ()); + + if (m_echo & ECHO_ALL) + { + // Echo is enabled for all functions, so turn it off + // for this one. + + m_echo_files[file] = false; + } + else + { + // Echo may be enabled for specific functions. + + auto p = m_echo_files.find (file); + + if (p == m_echo_files.end ()) + { + // Not this one, so enable it. + + m_echo |= ECHO_FUNCTIONS; + m_echo_files[file] = true; + } + else + { + // This one is already in the list. Flip the + // status for it. + + p->second = ! p->second; + } + } + } + } + break; + + case 2: + { + std::string arg0 = argv[0]; + std::string arg1 = argv[1]; + + if (arg1 == "on" || arg1 == "off") + std::swap (arg0, arg1); + + if (arg0 == "on") + { + if (arg1 == "all") + { + m_echo = (ECHO_SCRIPTS | ECHO_FUNCTIONS | ECHO_ALL); + m_echo_files.clear (); + } + else + { + std::string file = fcn_file_in_path (arg1); + file = sys::env::make_absolute (file); + + if (file.empty ()) + error ("echo: no such file %s", arg1.c_str ()); + + m_echo |= ECHO_FUNCTIONS; + m_echo_files[file] = true; + } + } + else if (arg0 == "off") + { + if (arg1 == "all") + { + m_echo = ECHO_OFF; + m_echo_files.clear (); + } + else + { + std::string file = fcn_file_in_path (arg1); + file = sys::env::make_absolute (file); + + if (file.empty ()) + error ("echo: no such file %s", arg1.c_str ()); + + m_echo_files[file] = false; + } + } + else + print_usage (); + } + break; + + default: + print_usage (); + break; + } + + return ovl (); + } + + octave_value + tree_evaluator::PS4 (const octave_value_list& args, int nargout) + { + return set_internal_variable (m_PS4, args, nargout, "PS4"); + } + + bool tree_evaluator::echo_this_file (const std::string& file, int type) const + { + if ((type & m_echo) == ECHO_SCRIPTS) + { + // Asking about scripts and echo is enabled for them. + return true; + } + + if ((type & m_echo) == ECHO_FUNCTIONS) + { + // Asking about functions and echo is enabled for functions. + // Now, which ones? + + auto p = m_echo_files.find (file); + + if (m_echo & ECHO_ALL) + { + // Return true ulness echo was turned off for a specific + // file. + + return (p == m_echo_files.end () || p->second); + } + else + { + // Return true if echo is specifically enabled for this file. + + return p != m_echo_files.end () && p->second; + } + } + + return false; + } + + void tree_evaluator::echo_code (size_t line) + { + std::string prefix = command_editor::decode_prompt_string (m_PS4); + + for (size_t i = m_echo_file_pos; i <= line; i++) + octave_stdout << prefix << get_file_line (m_echo_file_name, i) + << std::endl; + } } DEFMETHOD (max_recursion_depth, interp, args, nargout, @@ -2850,3 +3155,81 @@ %!error (string_fill_char (1, 2)) */ + +DEFMETHOD (PS4, interp, args, nargout, + doc: /* -*- texinfo -*- +@deftypefn {} {@var{val} =} PS4 () +@deftypefnx {} {@var{old_val} =} PS4 (@var{new_val}) +@deftypefnx {} {} PS4 (@var{new_val}, "local") +Query or set the character string used to prefix output produced +when echoing commands is enabled. + +The default value is @qcode{"+ "}. +@xref{Diary and Echo Commands}, for a description of echoing commands. + +When called from inside a function with the @qcode{"local"} option, the +variable is changed locally for the function and any subroutines it calls. +The original variable value is restored when exiting the function. +@seealso{echo, PS1, PS2} +@end deftypefn */) +{ + octave::tree_evaluator& tw = interp.get_evaluator (); + + return tw.PS4 (args, nargout); +} + +DEFMETHOD (echo, interp, args, nargout, + doc: /* -*- texinfo -*- +@deftypefn {} {} echo +@deftypefnx {} {} echo on +@deftypefnx {} {} echo off +@deftypefnx {} {} echo on all +@deftypefnx {} {} echo off all +@deftypefnx {} {} echo @var{function} on +@deftypefnx {} {} echo @var{function} off +Control whether commands are displayed as they are executed. + +Valid options are: + +@table @code +@item on +Enable echoing of commands as they are executed in script files. + +@item off +Disable echoing of commands as they are executed in script files. + +@item on all +Enable echoing of commands as they are executed in script files and +functions. + +@item off all +Disable echoing of commands as they are executed in script files and +functions. + +@item @var{function} on +Enable echoing of commands as they are executed in the named function. + +@item @var{function} off +Disable echoing of commands as they are executed in the named function. +@end table + +@noindent +With no arguments, @code{echo} toggles the current echo state. + +@seealso{PS4} +@end deftypefn */) +{ + octave::tree_evaluator& tw = interp.get_evaluator (); + + return tw.echo (args, nargout); +} + +/* +%!error echo ([]) +%!error echo (0) +%!error echo ("") +%!error echo ("Octave") +%!error echo ("off", "invalid") +%!error echo ("on", "invalid") +%!error echo ("on", "all", "all") +*/
--- a/libinterp/parse-tree/pt-eval.h Fri Jun 30 01:21:31 2017 -0400 +++ b/libinterp/parse-tree/pt-eval.h Fri Jun 30 20:59:54 2017 -0400 @@ -26,6 +26,7 @@ #include "octave-config.h" #include <list> +#include <set> #include <stack> #include <string> @@ -41,6 +42,7 @@ class tree_expression; class interpreter; + class unwind_protect; // How to evaluate the code that the parse trees represent. @@ -48,6 +50,14 @@ { public: + enum echo_state + { + ECHO_OFF = 0, + ECHO_SCRIPTS = 1, + ECHO_FUNCTIONS = 2, + ECHO_ALL = 4 + }; + template <typename T> class value_stack { @@ -107,7 +117,9 @@ : m_interpreter (interp), m_value_stack (), m_lvalue_list_stack (), m_nargout_stack (), m_call_stack (interp), m_max_recursion_depth (256), m_silent_functions (false), - m_string_fill_char (' ') + m_string_fill_char (' '), m_PS4 ("+ "), m_echo (ECHO_OFF), + m_echo_state (false), m_echo_file_name (), m_echo_file_pos (1), + m_echo_files () { } // No copying! @@ -331,6 +343,31 @@ return val; } + octave_value PS4 (const octave_value_list& args, int nargout); + + std::string PS4 (void) const { return m_PS4; } + + std::string PS4 (const std::string& s) + { + std::string val = m_PS4; + m_PS4 = s; + return val; + } + + octave_value echo (const octave_value_list& args, int nargout); + + int echo (void) const { return m_echo; } + + int echo (int val) + { + int old_val = m_echo; + m_echo = val; + return old_val; + } + + void push_echo_state (unwind_protect& frame, int type, + const std::string& file_name); + octave_value string_fill_char (const octave_value_list& args, int nargout); @@ -353,6 +390,25 @@ std::list<octave_lvalue> make_lvalue_list (tree_argument_list *); + // For unwind-protect. + void set_echo_state (bool val) { m_echo_state = val; } + + // For unwind-protect. + void set_echo_file_name (const std::string& file_name) + { + m_echo_file_name = file_name; + } + + // For unwind-protect. + void set_echo_file_pos (const size_t& file_pos) + { + m_echo_file_pos = file_pos; + } + + bool echo_this_file (const std::string& file, int type) const; + + void echo_code (size_t line); + interpreter& m_interpreter; value_stack<octave_value_list> m_value_stack; @@ -373,6 +429,26 @@ // The character to fill with when creating string arrays. char m_string_fill_char; + + // String printed before echoed commands (enabled by --echo-commands). + std::string m_PS4; + + // Echo commands as they are executed? + // + // 1 ==> echo commands read from script files + // 2 ==> echo commands from functions + // + // more than one state can be active at once. + int m_echo; + + // Are we currently echoing commands? This state is set by the + // functions that execute fucntions and scripts. + bool m_echo_state; + + std::string m_echo_file_name; + size_t m_echo_file_pos; + + std::map<std::string, bool> m_echo_files; }; }
--- a/libinterp/parse-tree/pt-stmt.cc Fri Jun 30 01:21:31 2017 -0400 +++ b/libinterp/parse-tree/pt-stmt.cc Fri Jun 30 20:59:54 2017 -0400 @@ -122,9 +122,9 @@ } void - tree_statement::echo_code (void) + tree_statement::echo_code (const std::string& prefix) { - tree_print_code tpc (octave_stdout, VPS4); + tree_print_code tpc (octave_stdout, prefix); accept (tpc); }
--- a/libinterp/parse-tree/pt-stmt.h Fri Jun 30 01:21:31 2017 -0400 +++ b/libinterp/parse-tree/pt-stmt.h Fri Jun 30 20:59:54 2017 -0400 @@ -85,7 +85,7 @@ void set_location (int l, int c); - void echo_code (void); + void echo_code (const std::string& prefix); tree_command * command (void) { return cmd; }