diff --git a/libinterp/parse-tree/lex.h b/libinterp/parse-tree/lex.h --- a/libinterp/parse-tree/lex.h +++ b/libinterp/parse-tree/lex.h @@ -347,11 +347,11 @@ namespace octave bool previous_token_may_be_command (void) const; - void maybe_mark_previous_token_as_variable (void); - void mark_as_variable (const std::string& nm); void mark_as_variables (const std::list& lst); + bool is_variable (const std::string& nm) const; + interpreter& m_interpreter; // true means that we have encountered eof on the input stream. @@ -515,8 +515,10 @@ namespace octave // current_function_level > 0 std::stack m_parsed_function_name; - // set of identifiers that might be local variable names. - std::set m_pending_local_variables; + // A list of sets of identifiers that might be local variable names. + // The front of the list corresponds to the current scope. The next + // element is for the parent scope, etc. + std::list> m_pending_local_variables; // Track current symbol table scope and context. symbol_table_context m_symtab_context; @@ -657,8 +659,6 @@ namespace octave bool inside_any_object_index (void); - bool is_variable (const std::string& name); - int make_keyword_token (const std::string& s); bool fq_identifier_contains_keyword (const std::string& s); diff --git a/libinterp/parse-tree/lex.ll b/libinterp/parse-tree/lex.ll --- a/libinterp/parse-tree/lex.ll +++ b/libinterp/parse-tree/lex.ll @@ -1817,8 +1817,6 @@ ANY_INCLUDING_NL (.|{NL}) "=" { curr_lexer->lexer_debug ("="); - curr_lexer->maybe_mark_previous_token_as_variable (); - return curr_lexer->handle_op ('='); } @@ -2353,19 +2351,34 @@ namespace octave } void - lexical_feedback::maybe_mark_previous_token_as_variable (void) + lexical_feedback::mark_as_variable (const std::string& nm) { - token *tok = m_tokens.front (); - - if (tok && tok->isstring ()) - m_pending_local_variables.insert (tok->text ()); + auto& vars = m_pending_local_variables.front (); + vars.insert (nm); } void lexical_feedback::mark_as_variables (const std::list& lst) { - for (const auto& var : lst) - m_pending_local_variables.insert (var); + auto& vars = m_pending_local_variables.front (); + for (const auto& nm : lst) + vars.insert (nm); + } + + bool + lexical_feedback::is_variable (const std::string& nm) const + { + if (m_interpreter.at_top_level () && m_interpreter.is_variable (nm)) + return true; + + // Search current scope, then parents. + for (const auto& vars : m_pending_local_variables) + { + if (vars.find (nm) != vars.end ()) + return true; + } + + return false; } } @@ -2656,15 +2669,6 @@ namespace octave return retval; } - bool - base_lexer::is_variable (const std::string& name) - { - return ((m_interpreter.at_top_level () - && m_interpreter.is_variable (name)) - || (m_pending_local_variables.find (name) - != m_pending_local_variables.end ())); - } - int base_lexer::make_keyword_token (const std::string& s) { diff --git a/libinterp/parse-tree/oct-parse.yy b/libinterp/parse-tree/oct-parse.yy --- a/libinterp/parse-tree/oct-parse.yy +++ b/libinterp/parse-tree/oct-parse.yy @@ -1451,7 +1451,8 @@ param_list_beg : '(' if (lexer.m_looking_at_function_handle) { // Will get a real name later. - lexer.m_symtab_context.push (octave::symbol_scope ("parser:param_lsit_beg")); + lexer.m_symtab_context.push (octave::symbol_scope ("parser:param_list_beg")); + lexer.m_pending_local_variables.push_front (std::set ()); lexer.m_looking_at_function_handle--; lexer.m_looking_at_anon_fcn_args = true; } @@ -1607,6 +1608,7 @@ push_script_symtab : // empty // This scope may serve as the parent scope for local // functions in classdef files.. lexer.m_symtab_context.push (octave::symbol_scope ("parser:push_script_symtab")); + lexer.m_pending_local_variables.push_front (std::set ()); } ; @@ -1628,6 +1630,7 @@ file : begin_file opt_nl opt_ // Unused symbol table context. lexer.m_symtab_context.pop (); + lexer.m_pending_local_variables.pop_front (); delete $3; } @@ -1650,6 +1653,7 @@ file : begin_file opt_nl opt_ // Unused symbol table context. lexer.m_symtab_context.pop (); + lexer.m_pending_local_variables.pop_front (); parser.finish_classdef_file ($3, $6); @@ -1952,6 +1956,7 @@ classdef_beg : CLASSDEF // Create invalid parent scope. lexer.m_symtab_context.push (octave::symbol_scope ()); + lexer.m_pending_local_variables.push_front (std::set ()); lexer.m_parsing_classdef = true; lexer.m_parsing_classdef_decl = true; lexer.m_classdef_element_names_are_keywords = true; @@ -2824,6 +2829,7 @@ namespace octave // Will get a real name later. m_lexer.m_symtab_context.push (symbol_scope ("parser:push_fcn_symtab")); + m_lexer.m_pending_local_variables.push_front (std::set ()); m_function_scopes.push (m_lexer.m_symtab_context.curr_scope ()); if (! m_lexer.m_reading_script_file && m_curr_fcn_depth == 0 @@ -2938,6 +2944,7 @@ namespace octave symbol_scope parent_scope = m_lexer.m_symtab_context.parent_scope (); m_lexer.m_symtab_context.pop (); + m_lexer.m_pending_local_variables.pop_front (); expr->set_print_flag (false); @@ -3428,6 +3435,8 @@ namespace octave { tree_expression *tmp = lhs->remove_front (); + m_lexer.mark_as_variable (tmp->name ()); + retval = new tree_simple_for_command (parfor, tmp, expr, maxproc, body, lc, tc, l, c); @@ -3444,9 +3453,11 @@ namespace octave bison_error ("invalid syntax for parfor statement"); } - else - retval = new tree_complex_for_command (lhs, expr, body, - lc, tc, l, c); + + m_lexer.mark_as_variables (lhs->variable_names ()); + + retval = new tree_complex_for_command (lhs, expr, body, + lc, tc, l, c); } } else @@ -3769,6 +3780,8 @@ namespace octave delete lhs; + m_lexer.mark_as_variable (tmp->name ()); + return new tree_simple_assignment (tmp, rhs, false, l, c, t); } else @@ -3789,6 +3802,8 @@ namespace octave } } + m_lexer.mark_as_variables (names); + return new tree_multi_assignment (lhs, rhs, false, l, c); } } @@ -3816,6 +3831,7 @@ namespace octave cmds, m_lexer.m_help_text); m_lexer.m_symtab_context.pop (); + m_lexer.m_pending_local_variables.pop_front (); m_lexer.m_help_text = ""; sys::time now; @@ -4216,6 +4232,7 @@ namespace octave base_parser::recover_from_parsing_function (void) { m_lexer.m_symtab_context.pop (); + m_lexer.m_pending_local_variables.pop_front (); if (m_lexer.m_reading_fcn_file && m_curr_fcn_depth == 0 && ! m_parsing_subfunctions) @@ -4251,6 +4268,7 @@ namespace octave tree_classdef *retval = nullptr; m_lexer.m_symtab_context.pop (); + m_lexer.m_pending_local_variables.pop_front (); std::string cls_name = id->name ();