Mercurial > octave
changeset 23343:49f051ef6f2f
local functions in classdef files (bug #41723)
* symtab.h, symtab.cc (symbol_table::fcn_info::fcn_info_rep::xfind):
Also handle file-local functions
(symbol_table::fcn_info::fcn_info_rep::x_builtin_find): Likewise.
(symbol_table::fcn_info::fcn_info_rep::dump): Display info about local
functions.
(symbol_table::fcn_info::fcn_info_rep::local_functions): New map.
(symbol_table::fcn_info::fcn_info_rep::fcn_info_rep): Initialize it.
(symbol_table::fcn_info::fcn_info_rep::install_local_funciton): New function.
(symbol_table::fcn_info::fcn_info_rep::clear): Clear local_functions map.
(symbol_table::fcn_info::install_local_function): New function.
(symbol_table::install_local_function): New function.
* parse.h, oct-parse.in.yy (fcn_list, fcn_list1, opt_fcn_list):
New non-terminals. Set parsing_local_functions after classdef is
recognized.
(file): Accept opt_fcn_list list after classdef object.
(base_parser::parsing_local_functions): New data member.
(base_parser::base_parser): Initialize it.
(base_parser::finish_function): Handle local functions.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Mon, 03 Apr 2017 16:21:19 -0400 |
parents | c70c0397ca2f |
children | 7dc148266dca |
files | libinterp/corefcn/symtab.cc libinterp/corefcn/symtab.h libinterp/parse-tree/oct-parse.in.yy libinterp/parse-tree/parse.h |
diffstat | 4 files changed, 157 insertions(+), 13 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/corefcn/symtab.cc Mon Apr 03 12:50:55 2017 -0400 +++ b/libinterp/corefcn/symtab.cc Mon Apr 03 16:21:19 2017 -0400 @@ -706,18 +706,42 @@ { if (local_funcs) { + octave_user_function *current_fcn = symbol_table::get_curr_fcn (); + + // Local function. + + if (current_fcn) + { + std::string fcn_file = current_fcn->fcn_file_name (); + + if (! fcn_file.empty ()) + { + str_val_iterator r = local_functions.find (fcn_file); + + if (r != local_functions.end ()) + { + // We shouldn't need an out-of-date check here since + // local functions may ultimately be called only from + // a primary function or method defined in the same + // file. + + return r->second; + } + } + } + // Subfunction. I think it only makes sense to check for // subfunctions if we are currently executing a function defined // from a .m file. - octave_user_function *current_fcn = symbol_table::get_curr_fcn (); - for (scope_id scope = xcurrent_scope; scope >= 0;) { scope_val_iterator r = subfunctions.find (scope); if (r != subfunctions.end ()) { - // FIXME: out-of-date check here. + // We shouldn't need an out-of-date check here since + // subfunctions may ultimately be called only from a + // primary function or method defined in the same file. return r->second; } @@ -941,6 +965,27 @@ } } + // Local function. + + if (current_fcn) + { + std::string fcn_file = current_fcn->fcn_file_name (); + + if (! fcn_file.empty ()) + { + str_val_iterator r = local_functions.find (fcn_file); + + if (r != local_functions.end ()) + { + // We shouldn't need an out-of-date check here since local + // functions may ultimately be called only from a primary + // function or method defined in the same file. + + return r->second; + } + } + } + // Subfunction. I think it only makes sense to check for // subfunctions if we are currently executing a function defined // from a .m file. @@ -950,7 +995,9 @@ scope_val_iterator r = subfunctions.find (scope); if (r != subfunctions.end ()) { - // FIXME: out-of-date check here. + // We shouldn't need an out-of-date check here since + // subfunctions may ultimately be called only from a primary + // function or method defined in the same file. return r->second; } @@ -1181,6 +1228,13 @@ << " [" << scope_val.first << "]\n"; } + if (! local_functions.empty ()) + { + for (const auto& str_val : local_functions) + os << tprefix << "local: " << fcn_file_name (str_val.second) + << " [" << str_val.first << "]\n"; + } + if (! private_functions.empty ()) { for (const auto& str_val : private_functions)
--- a/libinterp/corefcn/symtab.h Mon Apr 03 12:50:55 2017 -0400 +++ b/libinterp/corefcn/symtab.h Mon Apr 03 16:21:19 2017 -0400 @@ -747,10 +747,10 @@ public: fcn_info_rep (const std::string& nm) - : name (nm), package_name (), subfunctions (), private_functions (), - class_constructors (), class_methods (), cmdline_function (), - autoload_function (), function_on_path (), built_in_function (), - count (1) + : name (nm), package_name (), subfunctions (), local_functions (), + private_functions (), class_constructors (), class_methods (), + cmdline_function (), autoload_function (), function_on_path (), + built_in_function (), count (1) { size_t pos = name.rfind ('.'); @@ -767,6 +767,8 @@ fcn_info_rep& operator = (const fcn_info_rep&) = delete; + octave_value install_local_function (const std::string& file_name); + octave_value load_private_function (const std::string& dir_name); octave_value load_class_constructor (void); @@ -843,6 +845,12 @@ subfunctions[scope] = f; } + void install_local_function (const octave_value& f, + const std::string& file_name) + { + local_functions[file_name] = f; + } + void install_user_function (const octave_value& f) { function_on_path = f; @@ -903,6 +911,7 @@ void clear (bool force = false) { clear_map (subfunctions, force); + clear_map (local_functions, force); clear_map (private_functions, force); clear_map (class_constructors, force); clear_map (class_methods, force); @@ -929,6 +938,9 @@ // Scope id to function object. std::map<scope_id, octave_value> subfunctions; + // File name to function object. + std::map<std::string, octave_value> local_functions; + // Directory name to function object. std::map<std::string, octave_value> private_functions; @@ -1072,6 +1084,12 @@ rep->install_subfunction (f, scope); } + void install_local_function (const octave_value& f, + const std::string& file_name) + { + rep->install_local_function (f, file_name); + } + void install_user_function (const octave_value& f) { rep->install_user_function (f); @@ -1575,6 +1593,31 @@ inst->do_update_nest (); } + // Install local function FCN named NAME. FILE_NAME is the name of + // the file containing the local function. + + static void install_local_function (const std::string& name, + const octave_value& fcn, + const std::string& file_name) + { + fcn_table_iterator p = fcn_table.find (name); + + if (p != fcn_table.end ()) + { + fcn_info& finfo = p->second; + + finfo.install_local_function (fcn, file_name); + } + else + { + fcn_info finfo (name); + + finfo.install_local_function (fcn, file_name); + + fcn_table[name] = finfo; + } + } + static void install_user_function (const std::string& name, const octave_value& fcn) {
--- a/libinterp/parse-tree/oct-parse.in.yy Mon Apr 03 12:50:55 2017 -0400 +++ b/libinterp/parse-tree/oct-parse.in.yy Mon Apr 03 16:21:19 2017 -0400 @@ -231,6 +231,7 @@ // Nonterminals we construct. %type <dummy_type> indirect_ref_op decl_param_init push_fcn_symtab %type <dummy_type> param_list_beg param_list_end stmt_begin parse_error +%type <dummy_type> parsing_local_fcns %type <comment_type> stash_comment %type <tok_val> function_beg classdef_beg %type <punct_type> sep_no_nl opt_sep_no_nl nl opt_nl sep opt_sep @@ -269,6 +270,7 @@ %type <tree_statement_type> statement function_end %type <tree_statement_list_type> simple_list simple_list1 list list1 %type <tree_statement_list_type> opt_list +%type <tree_statement_list_type> opt_fcn_list fcn_list fcn_list1 %type <tree_classdef_attribute_type> attr %type <tree_classdef_attribute_list_type> attr_list opt_attr_list %type <tree_classdef_superclass_type> superclass @@ -431,6 +433,32 @@ { $$ = parser.append_statement_list ($1, $2, $3, true); } ; +opt_fcn_list : // empty + { $$ = 0; } + | fcn_list + { $$ = $1; } + ; + +fcn_list : fcn_list1 opt_sep + { + YYUSE ($2); + + $$ = $1; + } + ; + +fcn_list1 : function + { + octave::tree_statement *stmt = parser.make_statement ($1); + $$ = new octave::tree_statement_list (stmt); + } + | fcn_list1 opt_sep function + { + octave::tree_statement *stmt = parser.make_statement ($3); + $$ = parser.append_statement_list ($1, $2, stmt, false); + } + ; + statement : expression { $$ = parser.make_statement ($1); } | command @@ -1385,6 +1413,11 @@ // Script or function file // ======================= +parsing_local_fcns + : // empty + { parser.parsing_local_functions = true; } + ; + file : INPUT_FILE opt_nl opt_list END_OF_INPUT { YYUSE ($2); @@ -1411,10 +1444,11 @@ $$ = 0; } - | INPUT_FILE opt_nl classdef opt_sep END_OF_INPUT + | INPUT_FILE opt_nl classdef parsing_local_fcns opt_sep opt_fcn_list END_OF_INPUT { YYUSE ($2); - YYUSE ($4); + YYUSE ($5); + YYUSE ($6); if (lexer.reading_classdef_file) parser.classdef_object = $3; @@ -2108,7 +2142,8 @@ base_parser::base_parser (base_lexer& lxr) : endfunction_found (false), autoloading (false), - fcn_file_from_relative_lookup (false), parsing_subfunctions (false), + fcn_file_from_relative_lookup (false), + parsing_subfunctions (false), parsing_local_functions (false), max_fcn_depth (0), curr_fcn_depth (0), primary_fcn_scope (-1), curr_class_name (), curr_package_name (), function_scopes (), primary_fcn_ptr (0), subfunction_names (), classdef_object (0), @@ -2139,6 +2174,7 @@ autoloading = false; fcn_file_from_relative_lookup = false; parsing_subfunctions = false; + parsing_local_functions = false; max_fcn_depth = 0; curr_fcn_depth = 0; primary_fcn_scope = -1; @@ -3375,8 +3411,14 @@ } } - if (curr_fcn_depth == 1 && fcn) - symbol_table::update_nest (fcn->scope ()); + if (fcn) + { + if (parsing_local_functions ) + symbol_table::install_local_function (nm, octave_value (fcn), + file); + else if (curr_fcn_depth == 1) + symbol_table::update_nest (fcn->scope ()); + } if (! lexer.reading_fcn_file && curr_fcn_depth == 1) {
--- a/libinterp/parse-tree/parse.h Mon Apr 03 12:50:55 2017 -0400 +++ b/libinterp/parse-tree/parse.h Mon Apr 03 16:21:19 2017 -0400 @@ -413,6 +413,11 @@ // only be declared inside function files. bool parsing_subfunctions; + // TRUE if we are parsing local functions defined at after a + // classdef block. Local functions can only be declared inside + // classdef files. + bool parsing_local_functions; + // Maximum function depth detected. Used to determine whether // we have nested functions or just implicitly ended subfunctions. int max_fcn_depth;