# HG changeset patch # User John W. Eaton # Date 1499258265 14400 # Node ID 06b3d1d54054e2d4cb5d6b432ef5e0688668ce2f # Parent b40b7243a78245833de2dcc71cb17c7dbef96163 allow echo state to be modified from inside functions * ov-usr-fcn.h, ov-usr-fcn.cc (octave_user_code::curr_unwind_protect_frame, octave_user_code::unwind_protect_frame): Move variable and accessor function here from octave_user_function. (octave_user_script::call): Also unwind-protect and set current unwind_protect frame variable here. * pt-eval.h, pt-eval.cc (tree_evaluator::set_echo_state, tree_evaluator::maybe_set_echo_state, tree_evaluator::push_echo_state_cleanup, maybe_push_echo_state_cleanup): New functions. (tree_evaluator::push_echo_state): Call push_ech_state_cleanup and set_echo_state. (tree_evaluator::echo): Call maybe_push_echo_state_cleanup and set_echo_state. diff -r b40b7243a782 -r 06b3d1d54054 libinterp/octave-value/ov-usr-fcn.cc --- a/libinterp/octave-value/ov-usr-fcn.cc Wed Jul 05 09:44:01 2017 -0400 +++ b/libinterp/octave-value/ov-usr-fcn.cc Wed Jul 05 08:37:45 2017 -0400 @@ -157,6 +157,12 @@ cs.push (this); + // Set pointer to the current unwind_protect frame to allow + // certain builtins register simple cleanup in a very optimized manner. + // This is *not* intended as a general-purpose on-cleanup mechanism, + frame.protect_var (curr_unwind_protect_frame); + curr_unwind_protect_frame = &frame; + frame.add_method (cs, &octave::call_stack::pop); // Update line number even if debugging. @@ -214,7 +220,7 @@ subfunction (false), inline_function (false), anonymous_function (false), nested_function (false), class_constructor (none), class_method (false), - parent_scope (0), curr_unwind_protect_frame (0) + parent_scope (0) #if defined (HAVE_LLVM) , jit_info (0) #endif diff -r b40b7243a782 -r 06b3d1d54054 libinterp/octave-value/ov-usr-fcn.h --- a/libinterp/octave-value/ov-usr-fcn.h Wed Jul 05 09:44:01 2017 -0400 +++ b/libinterp/octave-value/ov-usr-fcn.h Wed Jul 05 08:37:45 2017 -0400 @@ -91,7 +91,6 @@ std::deque get_code_lines (size_t line, size_t num_lines); - virtual std::map subfunctions (void) const; virtual octave::tree_statement_list * body (void) = 0; @@ -388,12 +387,6 @@ void accept (octave::tree_walker& tw); - octave::unwind_protect * - unwind_protect_frame (void) - { - return curr_unwind_protect_frame; - } - #if defined (HAVE_LLVM) jit_function_info * get_info (void) { return jit_info; } @@ -487,9 +480,6 @@ // The scope of the parent function, if any. octave::symbol_table::scope *parent_scope; - // pointer to the current unwind_protect frame of this function. - octave::unwind_protect *curr_unwind_protect_frame; - #if defined (HAVE_LLVM) jit_function_info *jit_info; #endif diff -r b40b7243a782 -r 06b3d1d54054 libinterp/parse-tree/pt-eval.cc --- a/libinterp/parse-tree/pt-eval.cc Wed Jul 05 09:44:01 2017 -0400 +++ b/libinterp/parse-tree/pt-eval.cc Wed Jul 05 08:37:45 2017 -0400 @@ -2843,9 +2843,53 @@ "silent_functions"); } + 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"); + } + void tree_evaluator::push_echo_state (unwind_protect& frame, int type, - const std::string& file_name) + const std::string& file_name, + size_t pos) + { + push_echo_state_cleanup (frame); + + set_echo_state (type, file_name, pos); + } + + void + tree_evaluator::set_echo_state (int type, const std::string& file_name, + size_t pos) + { + m_echo_state = echo_this_file (file_name, type); + m_echo_file_name = file_name; + m_echo_file_pos = pos; + } + + void + tree_evaluator::maybe_set_echo_state (void) + { + octave_function *caller = m_call_stack.caller (); + + if (caller && caller->is_user_code ()) + { + octave_user_code *fcn = dynamic_cast (caller); + + int type = fcn->is_user_function () ? ECHO_FUNCTIONS : ECHO_SCRIPTS; + + std::string file_name = fcn->fcn_file_name (); + + size_t pos = m_call_stack.current_line (); + + set_echo_state (type, file_name, pos); + } + } + + void + tree_evaluator::push_echo_state_cleanup (unwind_protect& frame) { frame.add_method (*this, &tree_evaluator::set_echo_state, m_echo_state); @@ -2855,22 +2899,39 @@ 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) + bool tree_evaluator::maybe_push_echo_state_cleanup (void) { - return set_internal_variable (m_string_fill_char, args, nargout, - "string_fill_char"); + // This function is expected to be called from ECHO, which would be + // the top of the call stack. If the caller of ECHO is a + // user-defined fucntion or script, then set up unwind-protect + // elements to restore echo state. + + octave_function *caller = m_call_stack.caller (); + + if (caller && caller->is_user_code ()) + { + octave_user_code *fcn = dynamic_cast (caller); + + unwind_protect *frame = fcn->unwind_protect_frame (); + + if (frame) + { + push_echo_state_cleanup (*frame); + return true; + } + } + + return false; } + octave_value tree_evaluator::echo (const octave_value_list& args, int) { + bool cleanup_pushed = maybe_push_echo_state_cleanup (); + string_vector argv = args.make_argv (); switch (args.length ()) @@ -2988,6 +3049,9 @@ break; } + if (cleanup_pushed) + maybe_set_echo_state (); + return ovl (); } diff -r b40b7243a782 -r 06b3d1d54054 libinterp/parse-tree/pt-eval.h --- a/libinterp/parse-tree/pt-eval.h Wed Jul 05 09:44:01 2017 -0400 +++ b/libinterp/parse-tree/pt-eval.h Wed Jul 05 08:37:45 2017 -0400 @@ -365,14 +365,22 @@ 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); + void push_echo_state (unwind_protect& frame, int type, + const std::string& file_name, size_t pos = 1); + private: + void set_echo_state (int type, const std::string& file_name, size_t pos); + + void maybe_set_echo_state (void); + + void push_echo_state_cleanup (unwind_protect& frame); + + bool maybe_push_echo_state_cleanup (void); + void do_breakpoint (tree_statement& stmt) const; void do_breakpoint (bool is_breakpoint,