Mercurial > octave
diff libinterp/parse-tree/pt-eval.cc @ 22196:dd992fd74fce
put parser, lexer, and evaluator in namespace; interpreter now owns evaluator
* oct-parse.in.yy, parse.h: Move parser classes to octave namespace.
* lex.ll, lex.h: Move lexer classes to octave namespace.
* pt-eval.h, pt-eval.cc: Move evaluator class to octave namespace.
Don't define global current evaluator pointer here.
* debug.cc, error.cc, input.cc, input.h, ls-mat-ascii.cc, pt-jit.cc,
sighandlers.cc, utils.cc, variables.cc, ov-usr-fcn.cc, pt-assign.cc,
pt-exp.h, pt-id.cc: Update for namespaces.
* interpreter.cc, interpreter.h (current_evaluator): New global var.
(interpreter::m_evaluator): New data member.
(interpreter::~interpreter): Delete evaluator.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Tue, 12 Jul 2016 14:28:07 -0400 |
parents | 5d4a286061c8 |
children | bac0d6f07a3e |
line wrap: on
line diff
--- a/libinterp/parse-tree/pt-eval.cc Mon Aug 01 09:52:51 2016 -0700 +++ b/libinterp/parse-tree/pt-eval.cc Tue Jul 12 14:28:07 2016 -0400 @@ -49,23 +49,6 @@ //FIXME: This should be part of tree_evaluator #include "pt-jit.h" -static tree_evaluator std_evaluator; - -tree_evaluator *current_evaluator = &std_evaluator; - -int tree_evaluator::dbstep_flag = 0; - -size_t tree_evaluator::current_frame = 0; - -bool tree_evaluator::debug_mode = false; - -bool tree_evaluator::quiet_breakpoint_flag = false; - -tree_evaluator::stmt_list_type tree_evaluator::statement_context - = tree_evaluator::other; - -bool tree_evaluator::in_loop_command = false; - // Maximum nesting level for functions, scripts, or sourced files called // recursively. int Vmax_recursion_depth = 256; @@ -74,67 +57,83 @@ // semicolon has been appended to each statement). static bool Vsilent_functions = false; -// Normal evaluator. - -void -tree_evaluator::visit_anon_fcn_handle (tree_anon_fcn_handle&) +namespace octave { - panic_impossible (); -} + int tree_evaluator::dbstep_flag = 0; + + size_t tree_evaluator::current_frame = 0; + + bool tree_evaluator::debug_mode = false; -void -tree_evaluator::visit_argument_list (tree_argument_list&) -{ - panic_impossible (); -} + bool tree_evaluator::quiet_breakpoint_flag = false; + + tree_evaluator::stmt_list_type tree_evaluator::statement_context + = tree_evaluator::other; + + bool tree_evaluator::in_loop_command = false; + + // Normal evaluator. -void -tree_evaluator::visit_binary_expression (tree_binary_expression&) -{ - panic_impossible (); -} + void + tree_evaluator::visit_anon_fcn_handle (tree_anon_fcn_handle&) + { + panic_impossible (); + } -void -tree_evaluator::visit_break_command (tree_break_command& cmd) -{ - if (debug_mode) - do_breakpoint (cmd.is_breakpoint (true)); + void + tree_evaluator::visit_argument_list (tree_argument_list&) + { + panic_impossible (); + } - if (statement_context == function || statement_context == script - || in_loop_command) - tree_break_command::breaking = 1; -} + void + tree_evaluator::visit_binary_expression (tree_binary_expression&) + { + panic_impossible (); + } -void -tree_evaluator::visit_colon_expression (tree_colon_expression&) -{ - panic_impossible (); -} + void + tree_evaluator::visit_break_command (tree_break_command& cmd) + { + if (debug_mode) + do_breakpoint (cmd.is_breakpoint (true)); -void -tree_evaluator::visit_continue_command (tree_continue_command& cmd) -{ - if (debug_mode) - do_breakpoint (cmd.is_breakpoint (true)); + if (statement_context == function || statement_context == script + || in_loop_command) + tree_break_command::breaking = 1; + } + + void + tree_evaluator::visit_colon_expression (tree_colon_expression&) + { + panic_impossible (); + } - if (statement_context == function || statement_context == script - || in_loop_command) - tree_continue_command::continuing = 1; -} + void + tree_evaluator::visit_continue_command (tree_continue_command& cmd) + { + if (debug_mode) + do_breakpoint (cmd.is_breakpoint (true)); + + if (statement_context == function || statement_context == script + || in_loop_command) + tree_continue_command::continuing = 1; + } -void -tree_evaluator::reset_debug_state (void) -{ - debug_mode = bp_table::have_breakpoints () || Vdebugging; + void + tree_evaluator::reset_debug_state (void) + { + debug_mode = bp_table::have_breakpoints () || Vdebugging; - dbstep_flag = 0; -} + dbstep_flag = 0; + } -bool -tree_evaluator::statement_printing_enabled (void) -{ - return ! (Vsilent_functions && (statement_context == function - || statement_context == script)); + bool + tree_evaluator::statement_printing_enabled (void) + { + return ! (Vsilent_functions && (statement_context == function + || statement_context == script)); + } } static inline void @@ -191,71 +190,53 @@ } } -void -tree_evaluator::do_decl_init_list (decl_elt_init_fcn fcn, - tree_decl_init_list *init_list) +namespace octave { - if (init_list) - { - for (tree_decl_init_list::iterator p = init_list->begin (); - p != init_list->end (); p++) - { - tree_decl_elt *elt = *p; + void + tree_evaluator::do_decl_init_list (decl_elt_init_fcn fcn, + tree_decl_init_list *init_list) + { + if (init_list) + { + for (tree_decl_init_list::iterator p = init_list->begin (); + p != init_list->end (); p++) + { + tree_decl_elt *elt = *p; - fcn (*elt); - } - } -} + fcn (*elt); + } + } + } -void -tree_evaluator::visit_global_command (tree_global_command& cmd) -{ - if (debug_mode) - do_breakpoint (cmd.is_breakpoint (true)); - - do_decl_init_list (do_global_init, cmd.initializer_list ()); -} - -void -tree_evaluator::visit_persistent_command (tree_persistent_command& cmd) -{ - if (debug_mode) - do_breakpoint (cmd.is_breakpoint (true)); + void + tree_evaluator::visit_global_command (tree_global_command& cmd) + { + if (debug_mode) + do_breakpoint (cmd.is_breakpoint (true)); - do_decl_init_list (do_static_init, cmd.initializer_list ()); -} + do_decl_init_list (do_global_init, cmd.initializer_list ()); + } -void -tree_evaluator::visit_decl_elt (tree_decl_elt&) -{ - panic_impossible (); -} + void + tree_evaluator::visit_persistent_command (tree_persistent_command& cmd) + { + if (debug_mode) + do_breakpoint (cmd.is_breakpoint (true)); -#if 0 -bool -tree_decl_elt::eval (void) -{ - bool retval = false; + do_decl_init_list (do_static_init, cmd.initializer_list ()); + } - if (id && expr) - { - octave_lvalue ult = id->lvalue (); - - octave_value init_val = expr->rvalue1 (); - - ult.assign (octave_value::op_asn_eq, init_val); + void + tree_evaluator::visit_decl_elt (tree_decl_elt&) + { + panic_impossible (); + } - retval = true; - } - - return retval; -} -#endif - -void -tree_evaluator::visit_decl_init_list (tree_decl_init_list&) -{ - panic_impossible (); + void + tree_evaluator::visit_decl_init_list (tree_decl_init_list&) + { + panic_impossible (); + } } // Decide if it's time to quit a for or while loop. @@ -279,920 +260,922 @@ return quit; } -void -tree_evaluator::visit_simple_for_command (tree_simple_for_command& cmd) +namespace octave { - if (debug_mode) - do_breakpoint (cmd.is_breakpoint (true)); - - // FIXME: need to handle PARFOR loops here using cmd.in_parallel () - // and cmd.maxproc_expr (); + void + tree_evaluator::visit_simple_for_command (tree_simple_for_command& cmd) + { + if (debug_mode) + do_breakpoint (cmd.is_breakpoint (true)); - octave::unwind_protect frame; + // FIXME: need to handle PARFOR loops here using cmd.in_parallel () + // and cmd.maxproc_expr (); - frame.protect_var (in_loop_command); + octave::unwind_protect frame; - in_loop_command = true; + frame.protect_var (in_loop_command); + + in_loop_command = true; - tree_expression *expr = cmd.control_expr (); + tree_expression *expr = cmd.control_expr (); - octave_value rhs = expr->rvalue1 (); + octave_value rhs = expr->rvalue1 (); #if defined (HAVE_LLVM) - if (tree_jit::execute (cmd, rhs)) - return; + if (tree_jit::execute (cmd, rhs)) + return; #endif - if (rhs.is_undefined ()) - return; + if (rhs.is_undefined ()) + return; + + tree_expression *lhs = cmd.left_hand_side (); + + octave_lvalue ult = lhs->lvalue (); + + tree_statement_list *loop_body = cmd.body (); + + if (rhs.is_range ()) + { + Range rng = rhs.range_value (); + + octave_idx_type steps = rng.numel (); + + for (octave_idx_type i = 0; i < steps; i++) + { + octave_value val (rng.elem (i)); + + ult.assign (octave_value::op_asn_eq, val); + + if (loop_body) + loop_body->accept (*this); - tree_expression *lhs = cmd.left_hand_side (); + if (quit_loop_now ()) + break; + } + } + else if (rhs.is_scalar_type ()) + { + ult.assign (octave_value::op_asn_eq, rhs); + + if (loop_body) + loop_body->accept (*this); - octave_lvalue ult = lhs->lvalue (); + // Maybe decrement break and continue states. + quit_loop_now (); + } + else if (rhs.is_matrix_type () || rhs.is_cell () || rhs.is_string () + || rhs.is_map ()) + { + // A matrix or cell is reshaped to 2 dimensions and iterated by + // columns. + + dim_vector dv = rhs.dims ().redim (2); + + octave_idx_type nrows = dv(0); + octave_idx_type steps = dv(1); + + if (steps > 0) + { + octave_value arg = rhs; + if (rhs.ndims () > 2) + arg = arg.reshape (dv); - tree_statement_list *loop_body = cmd.body (); + // for row vectors, use single index to speed things up. + octave_value_list idx; + octave_idx_type iidx; + if (nrows == 1) + { + idx.resize (1); + iidx = 0; + } + else + { + idx.resize (2); + idx(0) = octave_value::magic_colon_t; + iidx = 1; + } + + for (octave_idx_type i = 1; i <= steps; i++) + { + // do_index_op expects one-based indices. + idx(iidx) = i; + octave_value val = arg.do_index_op (idx); + + ult.assign (octave_value::op_asn_eq, val); + + if (loop_body) + loop_body->accept (*this); + + if (quit_loop_now ()) + break; + } + } + } + else + error ("invalid type in for loop expression near line %d, column %d", + cmd.line (), cmd.column ()); + } - if (rhs.is_range ()) - { - Range rng = rhs.range_value (); + void + tree_evaluator::visit_complex_for_command (tree_complex_for_command& cmd) + { + if (debug_mode) + do_breakpoint (cmd.is_breakpoint (true)); + + octave::unwind_protect frame; + + frame.protect_var (in_loop_command); + + in_loop_command = true; + + tree_expression *expr = cmd.control_expr (); + + octave_value rhs = expr->rvalue1 (); + + if (rhs.is_undefined ()) + return; + + if (! rhs.is_map ()) + error ("in statement 'for [X, Y] = VAL', VAL must be a structure"); - octave_idx_type steps = rng.numel (); + // Cycle through structure elements. First element of id_list + // is set to value and the second is set to the name of the + // structure element. + + tree_argument_list *lhs = cmd.left_hand_side (); + + tree_argument_list::iterator p = lhs->begin (); + + tree_expression *elt = *p++; + + octave_lvalue val_ref = elt->lvalue (); + + elt = *p; + + octave_lvalue key_ref = elt->lvalue (); + + const octave_map tmp_val = rhs.map_value (); + + tree_statement_list *loop_body = cmd.body (); + + string_vector keys = tmp_val.keys (); + + octave_idx_type nel = keys.numel (); - for (octave_idx_type i = 0; i < steps; i++) - { - octave_value val (rng.elem (i)); + for (octave_idx_type i = 0; i < nel; i++) + { + std::string key = keys[i]; + + const Cell val_lst = tmp_val.contents (key); + + octave_idx_type n = val_lst.numel (); + + octave_value val = (n == 1) ? val_lst(0) : octave_value (val_lst); + + val_ref.assign (octave_value::op_asn_eq, val); + key_ref.assign (octave_value::op_asn_eq, key); + + if (loop_body) + loop_body->accept (*this); + + if (quit_loop_now ()) + break; + } + } + + void + tree_evaluator::visit_octave_user_script (octave_user_script&) + { + panic_impossible (); + } - ult.assign (octave_value::op_asn_eq, val); + void + tree_evaluator::visit_octave_user_function (octave_user_function&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_octave_user_function_header (octave_user_function&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_octave_user_function_trailer (octave_user_function&) + { + panic_impossible (); + } - if (loop_body) - loop_body->accept (*this); + void + tree_evaluator::visit_function_def (tree_function_def& cmd) + { + octave_value fcn = cmd.function (); + + octave_function *f = fcn.function_value (); + + if (f) + { + std::string nm = f->name (); + + symbol_table::install_cmdline_function (nm, fcn); + + // Make sure that any variable with the same name as the new + // function is cleared. + + symbol_table::assign (nm); + } + } - if (quit_loop_now ()) + void + tree_evaluator::visit_identifier (tree_identifier&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_if_clause (tree_if_clause&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_if_command (tree_if_command& cmd) + { + tree_if_command_list *lst = cmd.cmd_list (); + + if (lst) + lst->accept (*this); + } + + void + tree_evaluator::visit_if_command_list (tree_if_command_list& lst) + { + for (tree_if_command_list::iterator p = lst.begin (); p != lst.end (); p++) + { + tree_if_clause *tic = *p; + + tree_expression *expr = tic->condition (); + + if (statement_context == function || statement_context == script) + octave_call_stack::set_location (tic->line (), tic->column ()); + + if (debug_mode && ! tic->is_else_clause ()) + do_breakpoint (tic->is_breakpoint (true)); + + if (tic->is_else_clause () || expr->is_logically_true ("if")) + { + tree_statement_list *stmt_lst = tic->commands (); + + if (stmt_lst) + stmt_lst->accept (*this); + break; - } - } - else if (rhs.is_scalar_type ()) - { - ult.assign (octave_value::op_asn_eq, rhs); + } + } + } + + void + tree_evaluator::visit_index_expression (tree_index_expression&) + { + panic_impossible (); + } - if (loop_body) - loop_body->accept (*this); + void + tree_evaluator::visit_matrix (tree_matrix&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_cell (tree_cell&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_multi_assignment (tree_multi_assignment&) + { + panic_impossible (); + } - // Maybe decrement break and continue states. - quit_loop_now (); - } - else if (rhs.is_matrix_type () || rhs.is_cell () || rhs.is_string () - || rhs.is_map ()) - { - // A matrix or cell is reshaped to 2 dimensions and iterated by - // columns. + void + tree_evaluator::visit_no_op_command (tree_no_op_command& cmd) + { + if (debug_mode && cmd.is_end_of_fcn_or_script ()) + do_breakpoint (cmd.is_breakpoint (true), true); + } + + void + tree_evaluator::visit_constant (tree_constant&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_fcn_handle (tree_fcn_handle&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_funcall (tree_funcall&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_parameter_list (tree_parameter_list&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_postfix_expression (tree_postfix_expression&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_prefix_expression (tree_prefix_expression&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_return_command (tree_return_command& cmd) + { + if (debug_mode) + do_breakpoint (cmd.is_breakpoint (true)); + + // Act like dbcont. + + if (Vdebugging + && octave_call_stack::current_frame () == current_frame) + { + Vdebugging = false; + + reset_debug_state (); + } + else if (statement_context == function || statement_context == script + || in_loop_command) + tree_return_command::returning = 1; + } - dim_vector dv = rhs.dims ().redim (2); + void + tree_evaluator::visit_return_list (tree_return_list&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_simple_assignment (tree_simple_assignment&) + { + panic_impossible (); + } - octave_idx_type nrows = dv(0); - octave_idx_type steps = dv(1); + void + tree_evaluator::visit_statement (tree_statement& stmt) + { + tree_command *cmd = stmt.command (); + tree_expression *expr = stmt.expression (); + + if (cmd || expr) + { + if (statement_context == function || statement_context == script) + { + // Skip commands issued at a debug> prompt to avoid disturbing + // the state of the program we are debugging. + + if (Vtrack_line_num) + octave_call_stack::set_location (stmt.line (), stmt.column ()); - if (steps > 0) - { - octave_value arg = rhs; - if (rhs.ndims () > 2) - arg = arg.reshape (dv); + if ((statement_context == script + && ((Vecho_executing_commands & ECHO_SCRIPTS + && octave_call_stack::all_scripts ()) + || Vecho_executing_commands & ECHO_FUNCTIONS)) + || (statement_context == function + && Vecho_executing_commands & ECHO_FUNCTIONS)) + stmt.echo_code (); + } + + try + { + if (cmd) + cmd->accept (*this); + else + { + if (debug_mode) + do_breakpoint (expr->is_breakpoint (true)); + + // FIXME: maybe all of this should be packaged in + // one virtual function that returns a flag saying whether + // or not the expression will take care of binding ans and + // printing the result. + + // FIXME: it seems that we should just have to + // call expr->rvalue1 () and that should take care of + // everything, binding ans as necessary? + + bool do_bind_ans = false; + + if (expr->is_identifier ()) + { + tree_identifier *id = dynamic_cast<tree_identifier *> (expr); + + do_bind_ans = (! id->is_variable ()); + } + else + do_bind_ans = (! expr->is_assignment_expression ()); + + octave_value tmp_result = expr->rvalue1 (0); + + if (do_bind_ans && tmp_result.is_defined ()) + bind_ans (tmp_result, expr->print_result () + && statement_printing_enabled ()); - // for row vectors, use single index to speed things up. - octave_value_list idx; - octave_idx_type iidx; - if (nrows == 1) + // if (tmp_result.is_defined ()) + // result_values(0) = tmp_result; + } + } + catch (const std::bad_alloc&) + { + // FIXME: We want to use error_with_id here so that give users + // control over this error message but error_with_id will + // require some memory allocations. Is there anything we can + // do to make those more likely to succeed? + + error_with_id ("Octave:bad-alloc", + "out of memory or dimension too large for Octave's index type"); + } + } + } + + void + tree_evaluator::visit_statement_list (tree_statement_list& lst) + { + // FIXME: commented out along with else clause below. + // static octave_value_list empty_list; + + tree_statement_list::iterator p = lst.begin (); + + if (p != lst.end ()) + { + while (true) + { + tree_statement *elt = *p++; + + if (! elt) + error ("invalid statement found in statement list!"); + + octave_quit (); + + elt->accept (*this); + + if (tree_break_command::breaking + || tree_continue_command::continuing) + break; + + if (tree_return_command::returning) + break; + + if (p == lst.end ()) + break; + else + { + // Clear previous values before next statement is + // evaluated so that we aren't holding an extra + // reference to a value that may be used next. For + // example, in code like this: + // + // X = rand (N); # refcount for X should be 1 + // # after this statement + // + // X(idx) = val; # no extra copy of X should be + // # needed, but we will be faked + // # out if retval is not cleared + // # between statements here + + // result_values = empty_list; + } + } + } + } + + void + tree_evaluator::visit_switch_case (tree_switch_case&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_switch_case_list (tree_switch_case_list&) + { + panic_impossible (); + } + + void + tree_evaluator::visit_switch_command (tree_switch_command& cmd) + { + if (debug_mode) + do_breakpoint (cmd.is_breakpoint (true)); + + tree_expression *expr = cmd.switch_value (); + + if (! expr) + error ("missing value in switch command near line %d, column %d", + cmd.line (), cmd.column ()); + + octave_value val = expr->rvalue1 (); + + tree_switch_case_list *lst = cmd.case_list (); + + if (lst) + { + for (tree_switch_case_list::iterator p = lst->begin (); + p != lst->end (); p++) + { + tree_switch_case *t = *p; + + if (t->is_default_case () || t->label_matches (val)) + { + tree_statement_list *stmt_lst = t->commands (); + + if (stmt_lst) + stmt_lst->accept (*this); + + break; + } + } + } + } + + void + tree_evaluator::visit_try_catch_command (tree_try_catch_command& cmd) + { + bool execution_error = false; + + { // unwind frame before catch block + octave::unwind_protect frame; + + frame.protect_var (buffer_error_messages); + frame.protect_var (Vdebug_on_error); + frame.protect_var (Vdebug_on_warning); + + buffer_error_messages++; + Vdebug_on_error = false; + Vdebug_on_warning = false; + + // The catch code is *not* added to unwind_protect stack; + // it doesn't need to be run on interrupts. + + tree_statement_list *try_code = cmd.body (); + + if (try_code) + { + try { - idx.resize (1); - iidx = 0; - } - else - { - idx.resize (2); - idx(0) = octave_value::magic_colon_t; - iidx = 1; + in_try_catch++; + try_code->accept (*this); + in_try_catch--; } - - for (octave_idx_type i = 1; i <= steps; i++) + catch (const octave_execution_exception&) { - // do_index_op expects one-based indices. - idx(iidx) = i; - octave_value val = arg.do_index_op (idx); + recover_from_exception (); - ult.assign (octave_value::op_asn_eq, val); - - if (loop_body) - loop_body->accept (*this); - - if (quit_loop_now ()) - break; + in_try_catch--; // must be restored before "catch" block + execution_error = true; } } + // Unwind to let the user print any messages from + // errors that occurred in the body of the try_catch statement, + // or throw further errors. } - else - error ("invalid type in for loop expression near line %d, column %d", - cmd.line (), cmd.column ()); -} - -void -tree_evaluator::visit_complex_for_command (tree_complex_for_command& cmd) -{ - if (debug_mode) - do_breakpoint (cmd.is_breakpoint (true)); - - octave::unwind_protect frame; - - frame.protect_var (in_loop_command); - - in_loop_command = true; - - tree_expression *expr = cmd.control_expr (); - - octave_value rhs = expr->rvalue1 (); - - if (rhs.is_undefined ()) - return; - - if (! rhs.is_map ()) - error ("in statement 'for [X, Y] = VAL', VAL must be a structure"); - - // Cycle through structure elements. First element of id_list - // is set to value and the second is set to the name of the - // structure element. - - tree_argument_list *lhs = cmd.left_hand_side (); - - tree_argument_list::iterator p = lhs->begin (); - - tree_expression *elt = *p++; - - octave_lvalue val_ref = elt->lvalue (); - - elt = *p; - - octave_lvalue key_ref = elt->lvalue (); - - const octave_map tmp_val = rhs.map_value (); - - tree_statement_list *loop_body = cmd.body (); - - string_vector keys = tmp_val.keys (); - - octave_idx_type nel = keys.numel (); - - for (octave_idx_type i = 0; i < nel; i++) - { - std::string key = keys[i]; - - const Cell val_lst = tmp_val.contents (key); - - octave_idx_type n = val_lst.numel (); - - octave_value val = (n == 1) ? val_lst(0) : octave_value (val_lst); - - val_ref.assign (octave_value::op_asn_eq, val); - key_ref.assign (octave_value::op_asn_eq, key); - - if (loop_body) - loop_body->accept (*this); - - if (quit_loop_now ()) - break; - } -} - -void -tree_evaluator::visit_octave_user_script (octave_user_script&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_octave_user_function (octave_user_function&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_octave_user_function_header (octave_user_function&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_octave_user_function_trailer (octave_user_function&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_function_def (tree_function_def& cmd) -{ - octave_value fcn = cmd.function (); - - octave_function *f = fcn.function_value (); - - if (f) - { - std::string nm = f->name (); - - symbol_table::install_cmdline_function (nm, fcn); - // Make sure that any variable with the same name as the new - // function is cleared. - - symbol_table::assign (nm); - } -} - -void -tree_evaluator::visit_identifier (tree_identifier&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_if_clause (tree_if_clause&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_if_command (tree_if_command& cmd) -{ - tree_if_command_list *lst = cmd.cmd_list (); - - if (lst) - lst->accept (*this); -} - -void -tree_evaluator::visit_if_command_list (tree_if_command_list& lst) -{ - for (tree_if_command_list::iterator p = lst.begin (); p != lst.end (); p++) - { - tree_if_clause *tic = *p; - - tree_expression *expr = tic->condition (); - - if (statement_context == function || statement_context == script) - octave_call_stack::set_location (tic->line (), tic->column ()); - - if (debug_mode && ! tic->is_else_clause ()) - do_breakpoint (tic->is_breakpoint (true)); - - if (tic->is_else_clause () || expr->is_logically_true ("if")) - { - tree_statement_list *stmt_lst = tic->commands (); - - if (stmt_lst) - stmt_lst->accept (*this); - - break; - } - } -} + if (execution_error) + { + tree_statement_list *catch_code = cmd.cleanup (); + if (catch_code) + { + tree_identifier *expr_id = cmd.identifier (); + octave_lvalue ult; -void -tree_evaluator::visit_index_expression (tree_index_expression&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_matrix (tree_matrix&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_cell (tree_cell&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_multi_assignment (tree_multi_assignment&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_no_op_command (tree_no_op_command& cmd) -{ - if (debug_mode && cmd.is_end_of_fcn_or_script ()) - do_breakpoint (cmd.is_breakpoint (true), true); -} - -void -tree_evaluator::visit_constant (tree_constant&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_fcn_handle (tree_fcn_handle&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_funcall (tree_funcall&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_parameter_list (tree_parameter_list&) -{ - panic_impossible (); -} + if (expr_id) + { + ult = expr_id->lvalue (); -void -tree_evaluator::visit_postfix_expression (tree_postfix_expression&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_prefix_expression (tree_prefix_expression&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_return_command (tree_return_command& cmd) -{ - if (debug_mode) - do_breakpoint (cmd.is_breakpoint (true)); - - // Act like dbcont. - - if (Vdebugging - && octave_call_stack::current_frame () == current_frame) - { - Vdebugging = false; - - reset_debug_state (); - } - else if (statement_context == function || statement_context == script - || in_loop_command) - tree_return_command::returning = 1; -} - -void -tree_evaluator::visit_return_list (tree_return_list&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_simple_assignment (tree_simple_assignment&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_statement (tree_statement& stmt) -{ - tree_command *cmd = stmt.command (); - tree_expression *expr = stmt.expression (); + octave_scalar_map err; - if (cmd || expr) - { - if (statement_context == function || statement_context == script) - { - // Skip commands issued at a debug> prompt to avoid disturbing - // the state of the program we are debugging, but still track - // progress through user functions called from debug> prompt. - - if (Vtrack_line_num) - octave_call_stack::set_location (stmt.line (), stmt.column ()); - - if ((statement_context == script - && ((Vecho_executing_commands & ECHO_SCRIPTS - && octave_call_stack::all_scripts ()) - || Vecho_executing_commands & ECHO_FUNCTIONS)) - || (statement_context == function - && Vecho_executing_commands & ECHO_FUNCTIONS)) - stmt.echo_code (); - } + err.assign ("message", last_error_message ()); + err.assign ("identifier", last_error_id ()); + err.assign ("stack", last_error_stack ()); - try - { - if (cmd) - cmd->accept (*this); - else - { - if (debug_mode) - do_breakpoint (expr->is_breakpoint (true)); - - // FIXME: maybe all of this should be packaged in - // one virtual function that returns a flag saying whether - // or not the expression will take care of binding ans and - // printing the result. - - // FIXME: it seems that we should just have to - // call expr->rvalue1 () and that should take care of - // everything, binding ans as necessary? - - bool do_bind_ans = false; - - if (expr->is_identifier ()) - { - tree_identifier *id = dynamic_cast<tree_identifier *> (expr); - - do_bind_ans = (! id->is_variable ()); - } - else - do_bind_ans = (! expr->is_assignment_expression ()); - - octave_value tmp_result = expr->rvalue1 (0); - - if (do_bind_ans && tmp_result.is_defined ()) - bind_ans (tmp_result, expr->print_result () - && statement_printing_enabled ()); + ult.assign (octave_value::op_asn_eq, err); + } - // if (tmp_result.is_defined ()) - // result_values(0) = tmp_result; - } - } - catch (const std::bad_alloc&) - { - // FIXME: We want to use error_with_id here so that give users - // control over this error message but error_with_id will - // require some memory allocations. Is there anything we can - // do to make those more likely to succeed? - - error_with_id ("Octave:bad-alloc", - "out of memory or dimension too large for Octave's index type"); - } - } -} - -void -tree_evaluator::visit_statement_list (tree_statement_list& lst) -{ - // FIXME: commented out along with else clause below. - // static octave_value_list empty_list; - - tree_statement_list::iterator p = lst.begin (); - - if (p != lst.end ()) - { - while (true) - { - tree_statement *elt = *p++; - - if (! elt) - error ("invalid statement found in statement list!"); - - octave_quit (); - - elt->accept (*this); - - if (tree_break_command::breaking - || tree_continue_command::continuing) - break; - - if (tree_return_command::returning) - break; + // perform actual "catch" block + if (catch_code) + catch_code->accept (*this); + } + } + } - if (p == lst.end ()) - break; - else - { - // Clear previous values before next statement is - // evaluated so that we aren't holding an extra - // reference to a value that may be used next. For - // example, in code like this: - // - // X = rand (N); # refcount for X should be 1 - // # after this statement - // - // X(idx) = val; # no extra copy of X should be - // # needed, but we will be faked - // # out if retval is not cleared - // # between statements here - - // result_values = empty_list; - } - } - } -} - -void -tree_evaluator::visit_switch_case (tree_switch_case&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_switch_case_list (tree_switch_case_list&) -{ - panic_impossible (); -} - -void -tree_evaluator::visit_switch_command (tree_switch_command& cmd) -{ - if (debug_mode) - do_breakpoint (cmd.is_breakpoint (true)); - - tree_expression *expr = cmd.switch_value (); - - if (! expr) - error ("missing value in switch command near line %d, column %d", - cmd.line (), cmd.column ()); - - octave_value val = expr->rvalue1 (); - - tree_switch_case_list *lst = cmd.case_list (); - - if (lst) - { - for (tree_switch_case_list::iterator p = lst->begin (); - p != lst->end (); p++) - { - tree_switch_case *t = *p; - - if (t->is_default_case () || t->label_matches (val)) - { - tree_statement_list *stmt_lst = t->commands (); - - if (stmt_lst) - stmt_lst->accept (*this); - - break; - } - } - } -} - -void -tree_evaluator::visit_try_catch_command (tree_try_catch_command& cmd) -{ - bool execution_error = false; - - { // unwind frame before catch block + void + tree_evaluator::do_unwind_protect_cleanup_code (tree_statement_list *list) + { octave::unwind_protect frame; - frame.protect_var (buffer_error_messages); - frame.protect_var (Vdebug_on_error); - frame.protect_var (Vdebug_on_warning); + frame.protect_var (octave_interrupt_state); + octave_interrupt_state = 0; + + // We want to preserve the last location info for possible + // backtracking. + frame.add_fcn (octave_call_stack::set_line, + octave_call_stack::current_line ()); + frame.add_fcn (octave_call_stack::set_column, + octave_call_stack::current_column ()); + + // Similarly, if we have seen a return or break statement, allow all + // the cleanup code to run before returning or handling the break. + // We don't have to worry about continue statements because they can + // only occur in loops. + + frame.protect_var (tree_return_command::returning); + tree_return_command::returning = 0; + + frame.protect_var (tree_break_command::breaking); + tree_break_command::breaking = 0; + + try + { + if (list) + list->accept (*this); + } + catch (const octave_execution_exception&) + { + recover_from_exception (); + + if (tree_break_command::breaking || tree_return_command::returning) + frame.discard (2); + else + frame.run (2); + + frame.discard (2); + + throw; + } - buffer_error_messages++; - Vdebug_on_error = false; - Vdebug_on_warning = false; + // The unwind_protects are popped off the stack in the reverse of + // the order they are pushed on. - // The catch code is *not* added to unwind_protect stack; - // it doesn't need to be run on interrupts. + // FIXME: these statements say that if we see a break or + // return statement in the cleanup block, that we want to use the + // new value of the breaking or returning flag instead of restoring + // the previous value. Is that the right thing to do? I think so. + // Consider the case of + // + // function foo () + // unwind_protect + // fprintf (stderr, "1: this should always be executed\n"); + // break; + // fprintf (stderr, "1: this should never be executed\n"); + // unwind_protect_cleanup + // fprintf (stderr, "2: this should always be executed\n"); + // return; + // fprintf (stderr, "2: this should never be executed\n"); + // end_unwind_protect + // endfunction + // + // If we reset the value of the breaking flag, both the returning + // flag and the breaking flag will be set, and we shouldn't have + // both. So, use the most recent one. If there is no return or + // break in the cleanup block, the values should be reset to + // whatever they were when the cleanup block was entered. - tree_statement_list *try_code = cmd.body (); + if (tree_break_command::breaking || tree_return_command::returning) + frame.discard (2); + else + frame.run (2); + } - if (try_code) + void + tree_evaluator::visit_unwind_protect_command (tree_unwind_protect_command& cmd) + { + tree_statement_list *cleanup_code = cmd.cleanup (); + + tree_statement_list *unwind_protect_code = cmd.body (); + + if (unwind_protect_code) { try { - in_try_catch++; - try_code->accept (*this); - in_try_catch--; + unwind_protect_code->accept (*this); } catch (const octave_execution_exception&) { + // FIXME: Maybe we should be able to temporarily set the + // interpreter's exception handling state to something "safe" + // while the cleanup block runs instead of just resetting it + // here? recover_from_exception (); - in_try_catch--; // must be restored before "catch" block - execution_error = true; + // Run the cleanup code on exceptions, so that it is run even + // in case of interrupt or out-of-memory. + do_unwind_protect_cleanup_code (cleanup_code); + + // If an error occurs inside the cleanup code, a new + // exception will be thrown instead of the original. + throw; } + + // Also execute the unwind_protect_cleanump code if the + // unwind_protect block runs without error. + do_unwind_protect_cleanup_code (cleanup_code); } - // Unwind to let the user print any messages from - // errors that occurred in the body of the try_catch statement, - // or throw further errors. } - if (execution_error) - { - tree_statement_list *catch_code = cmd.cleanup (); - if (catch_code) - { - tree_identifier *expr_id = cmd.identifier (); - octave_lvalue ult; - - if (expr_id) - { - ult = expr_id->lvalue (); - - octave_scalar_map err; - - err.assign ("message", last_error_message ()); - err.assign ("identifier", last_error_id ()); - err.assign ("stack", last_error_stack ()); - - ult.assign (octave_value::op_asn_eq, err); - } - - // perform actual "catch" block - if (catch_code) - catch_code->accept (*this); - } - } -} - -void -tree_evaluator::do_unwind_protect_cleanup_code (tree_statement_list *list) -{ - octave::unwind_protect frame; - - frame.protect_var (octave_interrupt_state); - octave_interrupt_state = 0; + void + tree_evaluator::visit_while_command (tree_while_command& cmd) + { +#if defined (HAVE_LLVM) + if (tree_jit::execute (cmd)) + return; +#endif - // We want to preserve the last location info for possible - // backtracking. - frame.add_fcn (octave_call_stack::set_line, - octave_call_stack::current_line ()); - frame.add_fcn (octave_call_stack::set_column, - octave_call_stack::current_column ()); + octave::unwind_protect frame; - // Similarly, if we have seen a return or break statement, allow all - // the cleanup code to run before returning or handling the break. - // We don't have to worry about continue statements because they can - // only occur in loops. - - frame.protect_var (tree_return_command::returning); - tree_return_command::returning = 0; - - frame.protect_var (tree_break_command::breaking); - tree_break_command::breaking = 0; + frame.protect_var (in_loop_command); - try - { - if (list) - list->accept (*this); - } - catch (const octave_execution_exception&) - { - recover_from_exception (); + in_loop_command = true; - if (tree_break_command::breaking || tree_return_command::returning) - frame.discard (2); - else - frame.run (2); + tree_expression *expr = cmd.condition (); - frame.discard (2); - - throw; - } + if (! expr) + panic_impossible (); - // The unwind_protects are popped off the stack in the reverse of - // the order they are pushed on. + for (;;) + { + if (debug_mode) + do_breakpoint (cmd.is_breakpoint (true)); - // FIXME: these statements say that if we see a break or - // return statement in the cleanup block, that we want to use the - // new value of the breaking or returning flag instead of restoring - // the previous value. Is that the right thing to do? I think so. - // Consider the case of - // - // function foo () - // unwind_protect - // fprintf (stderr, "1: this should always be executed\n"); - // break; - // fprintf (stderr, "1: this should never be executed\n"); - // unwind_protect_cleanup - // fprintf (stderr, "2: this should always be executed\n"); - // return; - // fprintf (stderr, "2: this should never be executed\n"); - // end_unwind_protect - // endfunction - // - // If we reset the value of the breaking flag, both the returning - // flag and the breaking flag will be set, and we shouldn't have - // both. So, use the most recent one. If there is no return or - // break in the cleanup block, the values should be reset to - // whatever they were when the cleanup block was entered. + if (expr->is_logically_true ("while")) + { + tree_statement_list *loop_body = cmd.body (); - if (tree_break_command::breaking || tree_return_command::returning) - frame.discard (2); - else - frame.run (2); -} - -void -tree_evaluator::visit_unwind_protect_command (tree_unwind_protect_command& cmd) -{ - tree_statement_list *cleanup_code = cmd.cleanup (); + if (loop_body) + loop_body->accept (*this); - tree_statement_list *unwind_protect_code = cmd.body (); - - if (unwind_protect_code) - { - try - { - unwind_protect_code->accept (*this); - } - catch (const octave_execution_exception&) - { - // FIXME: Maybe we should be able to temporarily set the - // interpreter's exception handling state to something "safe" - // while the cleanup block runs instead of just resetting it - // here? - recover_from_exception (); + if (quit_loop_now ()) + break; + } + else + break; + } + } - // Run the cleanup code on exceptions, so that it is run even - // in case of interrupt or out-of-memory. - do_unwind_protect_cleanup_code (cleanup_code); - - // If an error occurs inside the cleanup code, a new - // exception will be thrown instead of the original. - throw; - } - - // Also execute the unwind_protect_cleanump code if the - // unwind_protect block runs without error. - do_unwind_protect_cleanup_code (cleanup_code); - } -} - -void -tree_evaluator::visit_while_command (tree_while_command& cmd) -{ + void + tree_evaluator::visit_do_until_command (tree_do_until_command& cmd) + { #if defined (HAVE_LLVM) - if (tree_jit::execute (cmd)) - return; + if (tree_jit::execute (cmd)) + return; #endif - octave::unwind_protect frame; - - frame.protect_var (in_loop_command); + octave::unwind_protect frame; - in_loop_command = true; + frame.protect_var (in_loop_command); - tree_expression *expr = cmd.condition (); + in_loop_command = true; - if (! expr) - panic_impossible (); + tree_expression *expr = cmd.condition (); + int until_line = cmd.line (); + int until_column = cmd.column (); - for (;;) - { - if (debug_mode) - do_breakpoint (cmd.is_breakpoint (true)); - - if (expr->is_logically_true ("while")) - { - tree_statement_list *loop_body = cmd.body (); + if (! expr) + panic_impossible (); - if (loop_body) - loop_body->accept (*this); + for (;;) + { + tree_statement_list *loop_body = cmd.body (); + + if (loop_body) + loop_body->accept (*this); - if (quit_loop_now ()) - break; - } - else - break; - } -} + if (quit_loop_now ()) + break; -void -tree_evaluator::visit_do_until_command (tree_do_until_command& cmd) -{ -#if defined (HAVE_LLVM) - if (tree_jit::execute (cmd)) - return; -#endif + if (debug_mode) + do_breakpoint (cmd.is_breakpoint (true)); - octave::unwind_protect frame; + octave_call_stack::set_location (until_line, until_column); - frame.protect_var (in_loop_command); - - in_loop_command = true; - - tree_expression *expr = cmd.condition (); - int until_line = cmd.line (); - int until_column = cmd.column (); + if (expr->is_logically_true ("do-until")) + break; + } + } - if (! expr) - panic_impossible (); - - for (;;) - { - tree_statement_list *loop_body = cmd.body (); - - if (loop_body) - loop_body->accept (*this); - - if (quit_loop_now ()) - break; + void + tree_evaluator::do_breakpoint (tree_statement& stmt) const + { + do_breakpoint (stmt.is_breakpoint (true), stmt.is_end_of_fcn_or_script ()); + } - if (debug_mode) - do_breakpoint (cmd.is_breakpoint (true)); - - octave_call_stack::set_location (until_line, until_column); + void + tree_evaluator::do_breakpoint (bool is_breakpoint, + bool is_end_of_fcn_or_script) const + { + bool break_on_this_statement = false; - if (expr->is_logically_true ("do-until")) - break; - } -} + if (octave_debug_on_interrupt_state) + { + break_on_this_statement = true; -void -tree_evaluator::do_breakpoint (tree_statement& stmt) const -{ - do_breakpoint (stmt.is_breakpoint (true), stmt.is_end_of_fcn_or_script ()); -} + octave_debug_on_interrupt_state = false; -void -tree_evaluator::do_breakpoint (bool is_breakpoint, - bool is_end_of_fcn_or_script) const -{ - bool break_on_this_statement = false; + current_frame = octave_call_stack::current_frame (); + } + else if (is_breakpoint) + { + break_on_this_statement = true; + + dbstep_flag = 0; - if (octave_debug_on_interrupt_state) - { - break_on_this_statement = true; - - octave_debug_on_interrupt_state = false; + current_frame = octave_call_stack::current_frame (); + } + else if (dbstep_flag > 0) + { + if (octave_call_stack::current_frame () == current_frame) + { + if (dbstep_flag == 1 || is_end_of_fcn_or_script) + { + // We get here if we are doing a "dbstep" or a "dbstep N" and the + // count has reached 1 so that we must stop and return to debug + // prompt. Alternatively, "dbstep N" has been used but the end + // of the frame has been reached so we stop at the last line and + // return to prompt. - current_frame = octave_call_stack::current_frame (); - } - else if (is_breakpoint) - { - break_on_this_statement = true; - - dbstep_flag = 0; + break_on_this_statement = true; - current_frame = octave_call_stack::current_frame (); - } - else if (dbstep_flag > 0) - { - if (octave_call_stack::current_frame () == current_frame) - { - if (dbstep_flag == 1 || is_end_of_fcn_or_script) - { - // We get here if we are doing a "dbstep" or a "dbstep N" and the - // count has reached 1 so that we must stop and return to debug - // prompt. Alternatively, "dbstep N" has been used but the end - // of the frame has been reached so we stop at the last line and - // return to prompt. + dbstep_flag = 0; + } + else + { + // Executing "dbstep N". Decrease N by one and continue. + + dbstep_flag--; + } - break_on_this_statement = true; + } + else if (dbstep_flag == 1 + && octave_call_stack::current_frame () < current_frame) + { + // We stepped out from the end of a function. - dbstep_flag = 0; - } - else - { - // Executing "dbstep N". Decrease N by one and continue. + current_frame = octave_call_stack::current_frame (); - dbstep_flag--; - } + break_on_this_statement = true; - } - else if (dbstep_flag == 1 - && octave_call_stack::current_frame () < current_frame) - { - // We stepped out from the end of a function. - - current_frame = octave_call_stack::current_frame (); - - break_on_this_statement = true; + dbstep_flag = 0; + } + } + else if (dbstep_flag == -1) + { + // We get here if we are doing a "dbstep in". - dbstep_flag = 0; - } - } - else if (dbstep_flag == -1) - { - // We get here if we are doing a "dbstep in". + break_on_this_statement = true; - break_on_this_statement = true; - - dbstep_flag = 0; + dbstep_flag = 0; - current_frame = octave_call_stack::current_frame (); - } - else if (dbstep_flag == -2) - { - // We get here if we are doing a "dbstep out". Check for end of - // function and whether the current frame is the same as the - // cached value because we want to step out from the frame where - // "dbstep out" was evaluated, not from any functions called from - // that frame. + current_frame = octave_call_stack::current_frame (); + } + else if (dbstep_flag == -2) + { + // We get here if we are doing a "dbstep out". Check for end of + // function and whether the current frame is the same as the + // cached value because we want to step out from the frame where + // "dbstep out" was evaluated, not from any functions called from + // that frame. + + if (is_end_of_fcn_or_script + && octave_call_stack::current_frame () == current_frame) + dbstep_flag = -1; + } - if (is_end_of_fcn_or_script - && octave_call_stack::current_frame () == current_frame) - dbstep_flag = -1; - } + if (break_on_this_statement) + do_keyboard (); - if (break_on_this_statement) - do_keyboard (); + } -} + // ARGS is currently unused, but since the do_keyboard function in + // input.cc accepts an argument list, we preserve it here so that the + // interface won't have to change if we decide to use it in the future. -// ARGS is currently unused, but since the do_keyboard function in -// input.cc accepts an argument list, we preserve it here so that the -// interface won't have to change if we decide to use it in the future. - -octave_value -tree_evaluator::do_keyboard (const octave_value_list& args) const -{ - return ::do_keyboard (args); + octave_value + tree_evaluator::do_keyboard (const octave_value_list& args) const + { + return ::do_keyboard (args); + } } DEFUN (max_recursion_depth, args, nargout,