1 //////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (C) 2012-2021 The Octave Project Developers 4 // 5 // See the file COPYRIGHT.md in the top-level directory of this 6 // distribution or <https://octave.org/copyright/>. 7 // 8 // This file is part of Octave. 9 // 10 // Octave is free software: you can redistribute it and/or modify it 11 // under the terms of the GNU General Public License as published by 12 // the Free Software Foundation, either version 3 of the License, or 13 // (at your option) any later version. 14 // 15 // Octave is distributed in the hope that it will be useful, but 16 // WITHOUT ANY WARRANTY; without even the implied warranty of 17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 // GNU General Public License for more details. 19 // 20 // You should have received a copy of the GNU General Public License 21 // along with Octave; see the file COPYING. If not, see 22 // <https://www.gnu.org/licenses/>. 23 // 24 //////////////////////////////////////////////////////////////////////// 25 26 #if defined (HAVE_CONFIG_H) 27 # include "config.h" 28 #endif 29 30 #include <algorithm> 31 #include <iomanip> 32 33 #include "cdef-class.h" 34 #include "cdef-manager.h" 35 #include "cdef-utils.h" 36 #include "errwarn.h" 37 #include "interpreter-private.h" 38 #include "interpreter.h" 39 #include "load-path.h" 40 #include "ov-builtin.h" 41 #include "ov-classdef.h" 42 #include "ov-fcn-handle.h" 43 #include "ov-usr-fcn.h" 44 #include "parse.h" 45 #include "pt-assign.h" 46 #include "pt-classdef.h" 47 #include "pt-idx.h" 48 #include "pt-misc.h" 49 #include "pt-stmt.h" 50 51 // Define to 1 to enable debugging statements. 52 #define DEBUG_TRACE 0 53 54 namespace octave 55 { 56 void install_class(const cdef_class & cls,const std::string & nm)57 cdef_package::cdef_package_rep::install_class (const cdef_class& cls, 58 const std::string& nm) 59 { 60 class_map[nm] = cls; 61 62 member_count++; 63 } 64 65 void install_function(const octave_value & fcn,const std::string & nm)66 cdef_package::cdef_package_rep::install_function (const octave_value& fcn, 67 const std::string& nm) 68 { 69 function_map[nm] = fcn; 70 } 71 72 void install_package(const cdef_package & pack,const std::string & nm)73 cdef_package::cdef_package_rep::install_package (const cdef_package& pack, 74 const std::string& nm) 75 { 76 package_map[nm] = pack; 77 78 member_count++; 79 } 80 81 template <typename T1, typename T2> 82 Cell map2Cell(const std::map<T1,T2> & m)83 map2Cell (const std::map<T1, T2>& m) 84 { 85 Cell retval (1, m.size ()); 86 int i = 0; 87 88 for (auto it = m.begin (); it != m.end (); ++it, ++i) 89 retval(i) = to_ov (it->second); 90 91 return retval; 92 } 93 94 Cell get_classes(void) const95 cdef_package::cdef_package_rep::get_classes (void) const 96 { 97 return map2Cell (class_map); 98 } 99 100 Cell get_functions(void) const101 cdef_package::cdef_package_rep::get_functions (void) const 102 { 103 return map2Cell (function_map); 104 } 105 106 Cell get_packages(void) const107 cdef_package::cdef_package_rep::get_packages (void) const 108 { 109 return map2Cell (package_map); 110 } 111 112 octave_value find(const std::string & nm)113 cdef_package::cdef_package_rep::find (const std::string& nm) 114 { 115 std::string symbol_name = get_name () + '.' + nm; 116 117 interpreter& interp 118 = __get_interpreter__ ("cdef_package::cdef_package_rep::find"); 119 120 return interp.find (symbol_name); 121 } 122 123 octave_value_list meta_subsref(const std::string & type,const std::list<octave_value_list> & idx,int nargout)124 cdef_package::cdef_package_rep::meta_subsref 125 (const std::string& type, const std::list<octave_value_list>& idx, 126 int nargout) 127 { 128 octave_value_list retval; 129 130 switch (type[0]) 131 { 132 case '.': 133 { 134 if (idx.front ().length () != 1) 135 error ("invalid meta.package indexing"); 136 137 std::string nm = idx.front ()(0).xstring_value ("invalid meta.package indexing, expected a symbol name"); 138 139 #if DEBUG_TRACE 140 std::cerr << "meta.package query: " << nm << std::endl; 141 #endif 142 143 octave_value o = find (nm); 144 145 if (! o.is_defined ()) 146 error ("member '%s' in package '%s' does not exist", 147 nm.c_str (), get_name ().c_str ()); 148 149 if (o.is_function ()) 150 { 151 octave_function *fcn = o.function_value (); 152 153 // NOTE: the case where the package query is the last 154 // part of this subsref index is handled in the parse 155 // tree, because there is some logic to handle magic 156 // "end" that makes it impossible to execute the 157 // function call at this stage. 158 159 if (type.size () > 1 160 && ! fcn->accepts_postfix_index (type[1])) 161 { 162 octave_value_list tmp_args; 163 164 retval = feval (o, tmp_args, nargout); 165 } 166 else 167 retval(0) = o; 168 169 if (type.size () > 1 && idx.size () > 1) 170 retval = retval(0).next_subsref (nargout, type, 171 idx, 1); 172 } 173 else if (type.size () > 1 && idx.size () > 1) 174 retval = o.next_subsref (nargout, type, idx, 1); 175 else 176 retval(0) = o; 177 } 178 break; 179 180 default: 181 error ("invalid meta.package indexing"); 182 break; 183 } 184 185 return retval; 186 } 187 188 void meta_release(void)189 cdef_package::cdef_package_rep::meta_release (void) 190 { 191 // FIXME: Do we really want to unregister the package, as it 192 // could still be referenced by classes or sub-packages? 193 // If the package object is recreated later on, it won't 194 // match the one already referenced by those classes or 195 // sub-packages. 196 197 cdef_manager& cdm 198 = __get_cdef_manager__ ("cdef_package::cdef_package_rep::meta_release"); 199 200 // Don't delete the "meta" package. 201 if (this != cdm.meta ().get_rep ()) 202 cdm.unregister_package (wrap ()); 203 } 204 } 205