# HG changeset patch # User John W. Eaton # Date 1386263080 18000 # Node ID 69ac19bb878e6a63647c3f8b79af0bb038701d22 # Parent 8cf2b8617e858dcc7b0d716f188e97b354df58c3# Parent 74dd974f7112063f27d3de7f866b446956d43331 maint: Merge classdef to default. diff -r 8cf2b8617e85 -r 69ac19bb878e libgui/languages/pt_BR.ts diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/Makefile.am diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/corefcn/load-path.cc --- a/libinterp/corefcn/load-path.cc Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/corefcn/load-path.cc Thu Dec 05 12:04:40 2013 -0500 @@ -120,6 +120,7 @@ if (fs) { method_file_map.clear (); + package_dir_map.clear (); dir_mtime = fs.mtime (); dir_time_last_checked = octave_time (); @@ -181,6 +182,8 @@ get_private_file_map (full_name); else if (fname[0] == '@') get_method_file_map (full_name, fname.substr (1)); + else if (fname[0] == '+') + get_package_dir (full_name, fname.substr (1)); } else { @@ -286,6 +289,13 @@ method_file_map[class_name].private_file_map = get_fcn_files (pd); } +void +load_path::dir_info::get_package_dir (const std::string& d, + const std::string& package_name) +{ + package_dir_map[package_name] = dir_info (d); +} + bool load_path::instance_ok (void) { @@ -373,8 +383,8 @@ } void -load_path::move_fcn_map (const std::string& dir_name, - const string_vector& fcn_files, bool at_end) +load_path::loader::move_fcn_map (const std::string& dir_name, + const string_vector& fcn_files, bool at_end) { octave_idx_type len = fcn_files.length (); @@ -422,7 +432,7 @@ } void -load_path::move_method_map (const std::string& dir_name, bool at_end) +load_path::loader::move_method_map (const std::string& dir_name, bool at_end) { for (method_map_iterator i = method_map.begin (); i != method_map.end (); @@ -466,7 +476,7 @@ } void -load_path::move (dir_info_list_iterator i, bool at_end) +load_path::do_move (dir_info_list_iterator i, bool at_end) { if (dir_info_list.size () > 1) { @@ -479,16 +489,56 @@ else dir_info_list.push_front (di); - std::string dir_name = di.dir_name; - - move_fcn_map (dir_name, di.fcn_files, at_end); - - // No need to move elements of private function map. - - move_method_map (dir_name, at_end); + move (di, at_end); + } +} + +void +load_path::move (const dir_info& di, bool at_end, const std::string& pname) +{ + loader& l = get_loader (pname); + + l.move (di, at_end); + + dir_info::package_dir_map_type package_dir_map = di.package_dir_map; + + for (dir_info::const_package_dir_map_iterator p = package_dir_map.begin (); + p != package_dir_map.end (); ++p) + { + std::string full_name = p->first; + + if (! pname.empty ()) + full_name = pname + "." + full_name; + + move (p->second, at_end, full_name); } } +void +load_path::loader::move (const dir_info& di, bool at_end) +{ + std::string dir_name = di.dir_name; + + std::list::iterator s = + std::find (dir_list.begin (), dir_list.end (), dir_name); + + if (s != dir_list.end ()) + { + dir_list.erase (s); + + if (at_end) + dir_list.push_back (dir_name); + else + dir_list.push_front (dir_name); + } + + move_fcn_map (dir_name, di.fcn_files, at_end); + + // No need to move elements of private function map. + + move_method_map (dir_name, at_end); +} + static void maybe_add_path_elts (std::string& path, const std::string& dir) { @@ -544,9 +594,10 @@ load_path::do_clear (void) { dir_info_list.clear (); - fcn_map.clear (); - private_fcn_map.clear (); - method_map.clear (); + + default_loader.clear (); + + loader_map.clear (); } static std::list @@ -683,7 +734,7 @@ dir_info_list_iterator i = find_dir_info (dir); if (i != dir_info_list.end ()) - move (i, at_end); + do_move (i, at_end); else { file_stat fs (dir); @@ -701,11 +752,7 @@ else dir_info_list.push_front (di); - add_to_fcn_map (di, at_end); - - add_to_private_fcn_map (di); - - add_to_method_map (di, at_end); + add (di, at_end); if (add_hook) add_hook (dir); @@ -726,12 +773,12 @@ i = find_dir_info ("."); if (i != dir_info_list.end ()) - move (i, false); + do_move (i, false); } void -load_path::remove_fcn_map (const std::string& dir, - const string_vector& fcn_files) +load_path::loader::remove_fcn_map (const std::string& dir, + const string_vector& fcn_files) { octave_idx_type len = fcn_files.length (); @@ -770,7 +817,7 @@ } void -load_path::remove_private_fcn_map (const std::string& dir) +load_path::loader::remove_private_fcn_map (const std::string& dir) { private_fcn_map_iterator p = private_fcn_map.find (dir); @@ -779,7 +826,7 @@ } void -load_path::remove_method_map (const std::string& dir) +load_path::loader::remove_method_map (const std::string& dir) { for (method_map_iterator i = method_map.begin (); i != method_map.end (); @@ -847,15 +894,11 @@ if (remove_hook) remove_hook (dir); - string_vector fcn_files = i->fcn_files; + dir_info& di = *i; + + remove (di); dir_info_list.erase (i); - - remove_fcn_map (dir, fcn_files); - - remove_private_fcn_map (dir); - - remove_method_map (dir); } } } @@ -864,17 +907,52 @@ } void +load_path::remove (const dir_info& di, const std::string& pname) +{ + loader& l = get_loader (pname); + + l.remove (di); + + dir_info::package_dir_map_type package_dir_map = di.package_dir_map; + + for (dir_info::const_package_dir_map_iterator p = package_dir_map.begin (); + p != package_dir_map.end (); ++p) + { + std::string full_name = p->first; + + if (! pname.empty ()) + full_name = pname + "." + full_name; + + remove (p->second, full_name); + } +} + +void +load_path::loader::remove (const dir_info& di) +{ + std::string dir = di.dir_name; + + string_vector fcn_files = di.fcn_files; + + dir_list.remove (dir); + + remove_fcn_map (dir, fcn_files); + + remove_private_fcn_map (dir); + + remove_method_map (dir); +} + +void load_path::do_update (void) const { // I don't see a better way to do this because we need to // preserve the correct directory ordering for new files that // have appeared. - fcn_map.clear (); - - private_fcn_map.clear (); - - method_map.clear (); + default_loader.clear (); + + loader_map.clear (); for (dir_info_list_iterator p = dir_info_list.begin (); p != dir_info_list.end (); @@ -884,11 +962,7 @@ di.update (); - add_to_fcn_map (di, true); - - add_to_private_fcn_map (di); - - add_to_method_map (di, true); + add (di, true); } } @@ -987,8 +1061,8 @@ } std::string -load_path::do_find_fcn (const std::string& fcn, std::string& dir_name, - int type) const +load_path::loader::find_fcn (const std::string& fcn, std::string& dir_name, + int type) const { std::string retval; @@ -1003,7 +1077,7 @@ std::string class_name = fcn.substr (1, pos-1); std::string meth = fcn.substr (pos+1); - retval = do_find_method (class_name, meth, dir_name); + retval = find_method (class_name, meth, dir_name); } else retval = std::string (); @@ -1042,8 +1116,8 @@ } std::string -load_path::do_find_private_fcn (const std::string& dir, - const std::string& fcn, int type) const +load_path::loader::find_private_fcn (const std::string& dir, + const std::string& fcn, int type) const { std::string retval; @@ -1072,9 +1146,9 @@ } std::string -load_path::do_find_method (const std::string& class_name, - const std::string& meth, - std::string& dir_name, int type) const +load_path::loader::find_method (const std::string& class_name, + const std::string& meth, + std::string& dir_name, int type) const { std::string retval; @@ -1120,7 +1194,7 @@ } std::list -load_path::do_methods (const std::string& class_name) const +load_path::loader::methods (const std::string& class_name) const { std::list retval; @@ -1149,16 +1223,34 @@ // update (); + default_loader.overloads (meth, retval); + + for (const_loader_map_iterator l = loader_map.begin (); + l != loader_map.end (); ++l) + l->second.overloads (meth, retval); + + return retval; +} + +void +load_path::loader::overloads (const std::string& meth, + std::list& l) const +{ for (const_method_map_iterator q = method_map.begin (); q != method_map.end (); q++) { const fcn_map_type& m = q->second; if (m.find (meth) != m.end ()) - retval.push_back (q->first); + { + std::string class_name = q->first; + + if (! prefix.empty ()) + class_name = prefix + "." + class_name; + + l.push_back (class_name); + } } - - return retval; } std::string @@ -1515,6 +1607,12 @@ string_vector load_path::do_fcn_names (void) const { + return default_loader.fcn_names (); +} + +string_vector +load_path::loader::fcn_names (void) const +{ size_t len = fcn_map.size (); string_vector retval (len); @@ -1657,69 +1755,11 @@ } } - for (const_private_fcn_map_iterator i = private_fcn_map.begin (); - i != private_fcn_map.end (); i++) - { - os << "\n*** private functions in " - << file_ops::concat (i->first, "private") << ":\n\n"; - - print_fcn_list (os, i->second); - } - -#if defined (DEBUG_LOAD_PATH) - - for (const_fcn_map_iterator i = fcn_map.begin (); - i != fcn_map.end (); - i++) - { - os << i->first << ":\n"; - - const file_info_list_type& file_info_list = i->second; - - for (const_file_info_list_iterator p = file_info_list.begin (); - p != file_info_list.end (); - p++) - { - os << " " << p->dir_name << " ("; - - print_types (os, p->types); - - os << ")\n"; - } - } - - for (const_method_map_iterator i = method_map.begin (); - i != method_map.end (); - i++) - { - os << "CLASS " << i->first << ":\n"; - - const fcn_map_type& fm = i->second; - - for (const_fcn_map_iterator q = fm.begin (); - q != fm.end (); - q++) - { - os << " " << q->first << ":\n"; - - const file_info_list_type& file_info_list = q->second; - - for (const_file_info_list_iterator p = file_info_list.begin (); - p != file_info_list.end (); - p++) - { - os << " " << p->dir_name << " ("; - - print_types (os, p->types); - - os << ")\n"; - } - } - } - - os << "\n"; - -#endif + default_loader.display (os); + + for (const_loader_map_iterator l = loader_map.begin (); + l != loader_map.end (); ++l) + l->second.display (os); } // True if a path is contained in a path list separated by path_sep_char @@ -1743,7 +1783,29 @@ } void -load_path::add_to_fcn_map (const dir_info& di, bool at_end) const +load_path::add (const dir_info& di, bool at_end, + const std::string& pname) const +{ + loader& l = get_loader (pname); + + l.add (di, at_end); + + dir_info::package_dir_map_type package_dir_map = di.package_dir_map; + + for (dir_info::const_package_dir_map_iterator p = package_dir_map.begin (); + p != package_dir_map.end (); ++p) + { + std::string full_name = p->first; + + if (! pname.empty ()) + full_name = pname + "." + full_name; + + add (p->second, at_end, full_name); + } +} + +void +load_path::loader::add_to_fcn_map (const dir_info& di, bool at_end) { std::string dir_name = di.dir_name; @@ -1839,7 +1901,7 @@ } void -load_path::add_to_private_fcn_map (const dir_info& di) const +load_path::loader::add_to_private_fcn_map (const dir_info& di) { dir_info::fcn_file_map_type private_file_map = di.private_file_map; @@ -1848,7 +1910,7 @@ } void -load_path::add_to_method_map (const dir_info& di, bool at_end) const +load_path::loader::add_to_method_map (const dir_info& di, bool at_end) { std::string dir_name = di.dir_name; @@ -1918,6 +1980,81 @@ } } +void +load_path::loader::display (std::ostream& os) const +{ + os << "*** loader: " << (prefix.empty () ? "" : prefix) << "\n\n"; + + for (std::list::const_iterator s = dir_list.begin (); + s != dir_list.end (); ++s) + os << *s << "\n"; + os << "\n"; + + for (const_private_fcn_map_iterator i = private_fcn_map.begin (); + i != private_fcn_map.end (); i++) + { + os << "\n*** private functions in " + << file_ops::concat (i->first, "private") << ":\n\n"; + + print_fcn_list (os, i->second); + } + +#if defined (DEBUG_LOAD_PATH) + + for (const_fcn_map_iterator i = fcn_map.begin (); + i != fcn_map.end (); + i++) + { + os << i->first << ":\n"; + + const file_info_list_type& file_info_list = i->second; + + for (const_file_info_list_iterator p = file_info_list.begin (); + p != file_info_list.end (); + p++) + { + os << " " << p->dir_name << " ("; + + print_types (os, p->types); + + os << ")\n"; + } + } + + for (const_method_map_iterator i = method_map.begin (); + i != method_map.end (); + i++) + { + os << "CLASS " << i->first << ":\n"; + + const fcn_map_type& fm = i->second; + + for (const_fcn_map_iterator q = fm.begin (); + q != fm.end (); + q++) + { + os << " " << q->first << ":\n"; + + const file_info_list_type& file_info_list = q->second; + + for (const_file_info_list_iterator p = file_info_list.begin (); + p != file_info_list.end (); + p++) + { + os << " " << p->dir_name << " ("; + + print_types (os, p->types); + + os << ")\n"; + } + } + } + + os << "\n"; + +#endif +} + std::string genpath (const std::string& dirname, const string_vector& skip) { @@ -1937,7 +2074,8 @@ { std::string elt = dirlist[i]; - bool skip_p = (elt == "." || elt == ".." || elt[0] == '@'); + bool skip_p = (elt == "." || elt == ".." || elt[0] == '@' + || elt[0] == '+'); if (! skip_p) { @@ -1964,6 +2102,21 @@ return retval; } +std::list +load_path::do_get_all_package_names (bool only_top_level) const +{ + std::list retval; + + for (const_loader_map_iterator l = loader_map.begin (); + l != loader_map.end (); ++l) + { + if (! only_top_level || l->first.find ('.') == std::string::npos) + retval.push_back (l->first); + } + + return retval; +} + static void execute_pkg_add_or_del (const std::string& dir, const std::string& script_file) @@ -2339,3 +2492,10 @@ return retval; } + +DEFUN (__dump_load_path__, , , "") +{ + load_path::display (octave_stdout); + + return octave_value_list (); +} diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/corefcn/load-path.h --- a/libinterp/corefcn/load-path.h Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/corefcn/load-path.h Thu Dec 05 12:04:40 2013 -0500 @@ -39,8 +39,7 @@ protected: load_path (void) - : dir_info_list (), fcn_map (), private_fcn_map (), method_map (), - init_dirs () { } + : loader_map (), default_loader (), dir_info_list (), init_dirs () { } public: @@ -96,24 +95,29 @@ static std::string find_method (const std::string& class_name, const std::string& meth, - std::string& dir_name) + std::string& dir_name, + const std::string& pack_name = std::string ()) { return instance_ok () - ? instance->do_find_method (class_name, meth, dir_name) - : std::string (); + ? instance->get_loader (pack_name).find_method (class_name, meth, + dir_name) + : std::string (); } static std::string find_method (const std::string& class_name, - const std::string& meth) + const std::string& meth, + const std::string& pack_name = std::string ()) { std::string dir_name; - return find_method (class_name, meth, dir_name); + return find_method (class_name, meth, dir_name, pack_name); } - static std::list methods (const std::string& class_name) + static std::list methods (const std::string& class_name, + const std::string& pack_name = std::string ()) { return instance_ok () - ? instance->do_methods (class_name) : std::list (); + ? instance->get_loader(pack_name).methods (class_name) + : std::list (); } static std::list overloads (const std::string& meth) @@ -122,47 +126,72 @@ ? instance->do_overloads (meth) : std::list (); } - static std::string find_fcn (const std::string& fcn, std::string& dir_name) + static bool find_package (const std::string& package_name) + { + return instance_ok () + ? instance->do_find_package (package_name) : false; + } + + static std::list + get_all_package_names (bool only_top_level = true) { return instance_ok () - ? instance->do_find_fcn (fcn, dir_name) : std::string (); + ? instance->do_get_all_package_names (only_top_level) + : std::list (); } - static std::string find_fcn (const std::string& fcn) + static std::string find_fcn (const std::string& fcn, std::string& dir_name, + const std::string& pack_name = std::string ()) + { + return instance_ok () + ? instance->get_loader (pack_name).find_fcn (fcn, dir_name) + : std::string (); + } + + static std::string find_fcn (const std::string& fcn, + const std::string& pack_name = std::string ()) { std::string dir_name; - return find_fcn (fcn, dir_name); + return find_fcn (fcn, dir_name, pack_name); } static std::string find_private_fcn (const std::string& dir, - const std::string& fcn) + const std::string& fcn, + const std::string& pack_name = std::string ()) { return instance_ok () - ? instance->do_find_private_fcn (dir, fcn) : std::string (); + ? instance->get_loader (pack_name).find_private_fcn (dir, fcn) + : std::string (); } - static std::string find_fcn_file (const std::string& fcn) + static std::string find_fcn_file (const std::string& fcn, + const std::string& pack_name = std::string ()) { std::string dir_name; - return instance_ok () ? - instance->do_find_fcn (fcn, dir_name, M_FILE) : std::string (); + return instance_ok () + ? instance->get_loader (pack_name).find_fcn (fcn, dir_name, M_FILE) + : std::string (); } - static std::string find_oct_file (const std::string& fcn) + static std::string find_oct_file (const std::string& fcn, + const std::string& pack_name = std::string ()) { std::string dir_name; - return instance_ok () ? - instance->do_find_fcn (fcn, dir_name, OCT_FILE) : std::string (); + return instance_ok () + ? instance->get_loader (pack_name).find_fcn (fcn, dir_name, M_FILE) + : std::string (); } - static std::string find_mex_file (const std::string& fcn) + static std::string find_mex_file (const std::string& fcn, + const std::string& pack_name = std::string ()) { std::string dir_name; - return instance_ok () ? - instance->do_find_fcn (fcn, dir_name, MEX_FILE) : std::string (); + return instance_ok () + ? instance->get_loader (pack_name).find_fcn (fcn, dir_name, M_FILE) + : std::string (); } static std::string find_file (const std::string& file) @@ -297,19 +326,27 @@ typedef method_file_map_type::const_iterator const_method_file_map_iterator; typedef method_file_map_type::iterator method_file_map_iterator; + // + typedef std::map package_dir_map_type; + + typedef package_dir_map_type::const_iterator const_package_dir_map_iterator; + typedef package_dir_map_type::iterator package_dir_map_iterator; + // This default constructor is only provided so we can create a // std::map of dir_info objects. You should not use this // constructor for any other purpose. dir_info (void) : dir_name (), abs_dir_name (), is_relative (false), dir_mtime (), dir_time_last_checked (), - all_files (), fcn_files (), private_file_map (), method_file_map () + all_files (), fcn_files (), private_file_map (), method_file_map (), + package_dir_map () { } dir_info (const std::string& d) : dir_name (d), abs_dir_name (), is_relative (false), dir_mtime (), dir_time_last_checked (), - all_files (), fcn_files (), private_file_map (), method_file_map () + all_files (), fcn_files (), private_file_map (), method_file_map (), + package_dir_map () { initialize (); } @@ -321,7 +358,8 @@ dir_time_last_checked (di.dir_time_last_checked), all_files (di.all_files), fcn_files (di.fcn_files), private_file_map (di.private_file_map), - method_file_map (di.method_file_map) { } + method_file_map (di.method_file_map), + package_dir_map (di.package_dir_map) { } ~dir_info (void) { } @@ -338,6 +376,7 @@ fcn_files = di.fcn_files; private_file_map = di.private_file_map; method_file_map = di.method_file_map; + package_dir_map = di.package_dir_map; } return *this; @@ -354,6 +393,7 @@ string_vector fcn_files; fcn_file_map_type private_file_map; method_file_map_type method_file_map; + package_dir_map_type package_dir_map; private: @@ -366,6 +406,9 @@ void get_method_file_map (const std::string& d, const std::string& class_name); + void get_package_dir (const std::string& d, + const std::string& package_name); + friend fcn_file_map_type get_fcn_files (const std::string& d); }; @@ -442,13 +485,125 @@ typedef method_map_type::const_iterator const_method_map_iterator; typedef method_map_type::iterator method_map_iterator; - mutable dir_info_list_type dir_info_list; + class loader + { + public: + loader (const std::string& pfx = std::string ()) + : prefix (pfx), dir_list (), fcn_map (), private_fcn_map (), + method_map () { } + + loader (const loader& l) + : prefix (l.prefix), dir_list (l.dir_list), + private_fcn_map (l.private_fcn_map), method_map (l.method_map) { } + + ~loader (void) { } + + loader& operator = (const loader& l) + { + if (&l != this) + { + prefix = l.prefix; + dir_list = l.dir_list; + fcn_map = l.fcn_map; + private_fcn_map = l.private_fcn_map; + method_map = l.method_map; + } + + return *this; + } - mutable fcn_map_type fcn_map; + void add (const dir_info& di, bool at_end) + { + if (at_end) + dir_list.push_back (di.dir_name); + else + dir_list.push_front (di.dir_name); + + add_to_fcn_map (di, at_end); + + add_to_private_fcn_map (di); + + add_to_method_map (di, at_end); + } + + void move (const dir_info& di, bool at_end); + + void remove (const dir_info& di); + + void clear (void) + { + dir_list.clear (); + + fcn_map.clear (); + + private_fcn_map.clear (); + + method_map.clear (); + } + + void display (std::ostream& out) const; - mutable private_fcn_map_type private_fcn_map; + std::string find_fcn (const std::string& fcn, + std::string& dir_name, + int type = M_FILE | OCT_FILE | MEX_FILE) const; + + std::string find_private_fcn (const std::string& dir, + const std::string& fcn, + int type = M_FILE | OCT_FILE | MEX_FILE) const; + + std::string find_method (const std::string& class_name, + const std::string& meth, + std::string& dir_name, + int type = M_FILE | OCT_FILE | MEX_FILE) const; + + std::list methods (const std::string& class_name) const; + + void overloads (const std::string& meth, std::list& l) const; + + string_vector fcn_names (void) const; + + private: + void add_to_fcn_map (const dir_info& di, bool at_end); + + void add_to_private_fcn_map (const dir_info& di); + + void add_to_method_map (const dir_info& di, bool at_end); + + void move_fcn_map (const std::string& dir, + const string_vector& fcn_files, bool at_end); + + void move_method_map (const std::string& dir, bool at_end); - mutable method_map_type method_map; + void remove_fcn_map (const std::string& dir, + const string_vector& fcn_files); + + void remove_private_fcn_map (const std::string& dir); + + void remove_method_map (const std::string& dir); + + private: + std::string prefix; + + std::list dir_list; + + fcn_map_type fcn_map; + + private_fcn_map_type private_fcn_map; + + method_map_type method_map; + }; + + // + typedef std::map loader_map_type; + + typedef loader_map_type::const_iterator const_loader_map_iterator; + typedef loader_map_type::iterator loader_map_iterator; + + mutable loader_map_type loader_map; + + mutable loader default_loader; + + mutable dir_info_list_type dir_info_list; mutable std::set init_dirs; @@ -475,12 +630,13 @@ bool do_contains_canonical (const std::string& dir) const; - void move_fcn_map (const std::string& dir, - const string_vector& fcn_files, bool at_end); + void do_move (dir_info_list_iterator i, bool at_end); - void move_method_map (const std::string& dir, bool at_end); + void move (const dir_info& di, bool at_end, + const std::string& pname = std::string ()); - void move (std::list::iterator i, bool at_end); + void remove (const dir_info& di, + const std::string& pname = std::string ()); void do_initialize (bool set_initial_path); @@ -494,12 +650,6 @@ void do_add (const std::string& dir, bool at_end, bool warn); - void remove_fcn_map (const std::string& dir, const string_vector& fcn_files); - - void remove_private_fcn_map (const std::string& dir); - - void remove_method_map (const std::string& dir); - bool do_remove (const std::string& dir); void do_update (void) const; @@ -508,23 +658,31 @@ check_file_type (std::string& fname, int type, int possible_types, const std::string& fcn, const char *who); - std::string do_find_fcn (const std::string& fcn, - std::string& dir_name, - int type = M_FILE | OCT_FILE | MEX_FILE) const; + loader& get_loader (const std::string& name) const + { + if (! name.empty ()) + { + loader_map_iterator l = loader_map.find (name); - std::string do_find_private_fcn (const std::string& dir, - const std::string& fcn, - int type = M_FILE | OCT_FILE | MEX_FILE) const; + if (l == loader_map.end ()) + l = loader_map.insert (loader_map.end (), + loader_map_type::value_type (name, loader (name))); - std::string do_find_method (const std::string& class_name, - const std::string& meth, - std::string& dir_name, - int type = M_FILE | OCT_FILE | MEX_FILE) const; + return l->second; + } - std::list do_methods (const std::string& class_name) const; + return default_loader; + } std::list do_overloads (const std::string& meth) const; + bool do_find_package (const std::string& package_name) const + { + return (loader_map.find (package_name) != loader_map.end ()); + } + + std::list do_get_all_package_names (bool only_top_level) const; + std::string do_find_file (const std::string& file) const; std::string do_find_dir (const std::string& dir) const; @@ -559,11 +717,8 @@ std::string do_get_command_line_path (void) const { return command_line_path; } - void add_to_fcn_map (const dir_info& di, bool at_end) const; - - void add_to_private_fcn_map (const dir_info& di) const; - - void add_to_method_map (const dir_info& di, bool at_end) const; + void add (const dir_info& di, bool at_end, + const std::string& pname = std::string ()) const; friend dir_info::fcn_file_map_type get_fcn_files (const std::string& d); }; diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/corefcn/ls-mat5.cc --- a/libinterp/corefcn/ls-mat5.cc Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/corefcn/ls-mat5.cc Thu Dec 05 12:04:40 2013 -0500 @@ -929,7 +929,7 @@ std::string dir_name = str.substr (0, xpos); octave_function *fcn - = load_fcn_from_file (str, dir_name, "", fname); + = load_fcn_from_file (str, dir_name, "", "", fname); if (fcn) { @@ -958,7 +958,7 @@ std::string dir_name = str.substr (0, xpos); octave_function *fcn - = load_fcn_from_file (str, dir_name, "", fname); + = load_fcn_from_file (str, dir_name, "", "", fname); if (fcn) { @@ -983,7 +983,7 @@ std::string dir_name = fpath.substr (0, xpos); octave_function *fcn - = load_fcn_from_file (fpath, dir_name, "", fname); + = load_fcn_from_file (fpath, dir_name, "", "", fname); if (fcn) { diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/corefcn/pt-jit.cc --- a/libinterp/corefcn/pt-jit.cc Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/corefcn/pt-jit.cc Thu Dec 05 12:04:40 2013 -0500 @@ -683,6 +683,12 @@ } void +jit_convert::visit_funcall (tree_funcall&) +{ + throw jit_fail_exception (); +} + +void jit_convert::visit_parameter_list (tree_parameter_list&) { throw jit_fail_exception (); diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/corefcn/pt-jit.h --- a/libinterp/corefcn/pt-jit.h Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/corefcn/pt-jit.h Thu Dec 05 12:04:40 2013 -0500 @@ -129,6 +129,8 @@ void visit_fcn_handle (tree_fcn_handle&); + void visit_funcall (tree_funcall&); + void visit_parameter_list (tree_parameter_list&); void visit_postfix_expression (tree_postfix_expression&); diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/corefcn/symtab.cc --- a/libinterp/corefcn/symtab.cc Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/corefcn/symtab.cc Thu Dec 05 12:04:40 2013 -0500 @@ -38,6 +38,7 @@ #include "dirfns.h" #include "input.h" #include "load-path.h" +#include "ov-classdef.h" #include "ov-fcn.h" #include "ov-usr-fcn.h" #include "pager.h" @@ -383,11 +384,13 @@ std::string dir_name; - std::string file_name = load_path::find_method (name, name, dir_name); + std::string file_name = load_path::find_method (name, name, dir_name, + package_name); if (! file_name.empty ()) { - octave_function *fcn = load_fcn_from_file (file_name, dir_name, name); + octave_function *fcn = load_fcn_from_file (file_name, dir_name, name, + package_name); if (fcn) { @@ -396,6 +399,31 @@ class_constructors[name] = retval; } } + else + { + // Classdef constructors can be defined anywhere in the path, not + // necessarily in @-folders. Look for a normal function and load it. + // If the loaded function is a classdef constructor, store it as such + // and restore function_on_path to its previous value. + + octave_value old_function_on_path = function_on_path; + + octave_value maybe_cdef_ctor = find_user_function (); + + if (maybe_cdef_ctor.is_defined ()) + { + octave_function *fcn = maybe_cdef_ctor.function_value (true); + + if (fcn && fcn->is_classdef_constructor ()) + { + retval = maybe_cdef_ctor; + + class_constructors[name] = retval; + + function_on_path = old_function_on_path; + } + } + } return retval; } @@ -406,47 +434,57 @@ { octave_value retval; - if (name == dispatch_type) + if (full_name () == dispatch_type) retval = load_class_constructor (); else { - std::string dir_name; + octave_function *cm = cdef_manager::find_method_symbol (name, + dispatch_type); - std::string file_name = load_path::find_method (dispatch_type, name, - dir_name); + if (cm) + retval = octave_value (cm); - if (! file_name.empty ()) + if (! retval.is_defined ()) { - octave_function *fcn = load_fcn_from_file (file_name, dir_name, - dispatch_type); + std::string dir_name; - if (fcn) + std::string file_name = load_path::find_method (dispatch_type, name, + dir_name); + + if (! file_name.empty ()) { - retval = octave_value (fcn); + octave_function *fcn = load_fcn_from_file (file_name, dir_name, + dispatch_type); - class_methods[dispatch_type] = retval; - } - } + if (fcn) + { + retval = octave_value (fcn); - if (retval.is_undefined ()) - { - // Search parent classes + class_methods[dispatch_type] = retval; + } + } - const std::list& plist = parent_classes (dispatch_type); - - std::list::const_iterator it = plist.begin (); - - while (it != plist.end ()) + if (retval.is_undefined ()) { - retval = find_method (*it); + // Search parent classes - if (retval.is_defined ()) + const std::list& plist = + parent_classes (dispatch_type); + + std::list::const_iterator it = plist.begin (); + + while (it != plist.end ()) { - class_methods[dispatch_type] = retval; - break; + retval = find_method (*it); + + if (retval.is_defined ()) + { + class_methods[dispatch_type] = retval; + break; + } + + it++; } - - it++; } } } @@ -787,6 +825,13 @@ if (fcn.is_defined ()) return fcn; + // Package + + fcn = find_package (); + + if (fcn.is_defined ()) + return fcn; + // Built-in function (might be undefined). return built_in_function; @@ -975,7 +1020,7 @@ std::string dir_name = file_name.substr (0, pos); - octave_function *fcn = load_fcn_from_file (file_name, dir_name, + octave_function *fcn = load_fcn_from_file (file_name, dir_name, "", "", name, true); if (fcn) @@ -998,11 +1043,13 @@ { std::string dir_name; - std::string file_name = load_path::find_fcn (name, dir_name); + std::string file_name = load_path::find_fcn (name, dir_name, + package_name); if (! file_name.empty ()) { - octave_function *fcn = load_fcn_from_file (file_name, dir_name); + octave_function *fcn = load_fcn_from_file (file_name, dir_name, "", + package_name); if (fcn) function_on_path = octave_value (fcn); @@ -1012,6 +1059,25 @@ return function_on_path; } +octave_value +symbol_table::fcn_info::fcn_info_rep::find_package (void) +{ + // FIXME: implement correct way to check out of date package + //if (package.is_defined ()) + // out_of_date_check (package); + + if (! (error_state || package.is_defined ())) + { + octave_function * fcn = + cdef_manager::find_package_symbol (full_name ()); + + if (fcn) + package = octave_value (fcn); + } + + return package; +} + // Insert INF_CLASS in the set of class names that are considered // inferior to SUP_CLASS. Return FALSE if INF_CLASS is currently // marked as superior to SUP_CLASS. @@ -1069,10 +1135,11 @@ symbol_table::fcn_info::fcn_info_rep::dump (std::ostream& os, const std::string& prefix) const { - os << prefix << name + os << prefix << full_name () << " [" << (cmdline_function.is_defined () ? "c" : "") << (built_in_function.is_defined () ? "b" : "") + << (package.is_defined () ? "p" : "") << "]\n"; std::string tprefix = prefix + " "; diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/corefcn/symtab.h --- a/libinterp/corefcn/symtab.h Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/corefcn/symtab.h Thu Dec 05 12:04:40 2013 -0500 @@ -756,10 +756,19 @@ public: fcn_info_rep (const std::string& nm) - : name (nm), subfunctions (), private_functions (), + : name (nm), package_name (), subfunctions (), private_functions (), class_constructors (), class_methods (), dispatch_map (), cmdline_function (), autoload_function (), function_on_path (), - built_in_function (), count (1) { } + built_in_function (), count (1) + { + size_t pos = name.rfind ('.'); + + if (pos != std::string::npos) + { + package_name = name.substr (0, pos); + name = name.substr (pos+1); + } + } octave_value load_private_function (const std::string& dir_name); @@ -775,6 +784,8 @@ octave_value find_autoload (void); + octave_value find_package (void); + octave_value find_user_function (void); bool is_user_function_defined (void) const @@ -883,6 +894,11 @@ clear_user_function (); } + void clear_package (void) + { + package = octave_value (); + } + void clear (bool force = false) { clear_map (subfunctions, force); @@ -892,6 +908,7 @@ clear_autoload_function (force); clear_user_function (force); + clear_package (); } void add_dispatch (const std::string& type, const std::string& fname) @@ -915,8 +932,18 @@ void dump (std::ostream& os, const std::string& prefix) const; + std::string full_name (void) const + { + if (package_name.empty ()) + return name; + else + return package_name + "." + name; + } + std::string name; + std::string package_name; + // Scope id to function object. std::map subfunctions; @@ -938,6 +965,8 @@ octave_value function_on_path; + octave_value package; + octave_value built_in_function; octave_refcount count; diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/octave-value/module.mk --- a/libinterp/octave-value/module.mk Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/octave-value/module.mk Thu Dec 05 12:04:40 2013 -0500 @@ -36,6 +36,7 @@ octave-value/ov-cell.h \ octave-value/ov-ch-mat.h \ octave-value/ov-class.h \ + octave-value/ov-classdef.h \ octave-value/ov-colon.h \ octave-value/ov-complex.h \ octave-value/ov-cs-list.h \ @@ -94,6 +95,7 @@ octave-value/ov-cell.cc \ octave-value/ov-ch-mat.cc \ octave-value/ov-class.cc \ + octave-value/ov-classdef.cc \ octave-value/ov-colon.cc \ octave-value/ov-complex.cc \ octave-value/ov-cs-list.cc \ diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/octave-value/ov-classdef.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/octave-value/ov-classdef.cc Thu Dec 05 12:04:40 2013 -0500 @@ -0,0 +1,3608 @@ +/* + +Copyright (C) 2012-2013 Michael Goffioul + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "defun.h" +#include "load-path.h" +#include "ov-builtin.h" +#include "ov-classdef.h" +#include "ov-fcn-handle.h" +#include "ov-typeinfo.h" +#include "pt-assign.h" +#include "pt-classdef.h" +#include "pt-funcall.h" +#include "pt-misc.h" +#include "pt-stmt.h" +#include "pt-walk.h" +#include "singleton-cleanup.h" +#include "symtab.h" +#include "toplev.h" + +#include "Array.cc" + +static void +gripe_method_access (const std::string& from, const cdef_method& meth) +{ + octave_value acc = meth.get ("Access"); + std::string acc_s; + + if (acc.is_string ()) + acc_s = acc.string_value (); + else + acc_s = "class-restricted"; + + error ("%s: method `%s' has %s access and cannot be run in this context", + from.c_str (), meth.get_name ().c_str (), acc_s.c_str ()); +} + +static void +gripe_property_access (const std::string& from, const cdef_property& prop, + bool is_set = false) +{ + octave_value acc = prop.get (is_set ? "SetAccess" : "GetAccess"); + std::string acc_s; + + if (acc.is_string ()) + acc_s = acc.string_value (); + else + acc_s = "class-restricted"; + + if (is_set) + error ("%s: property `%s' has %s access and cannot be set in this context", + from.c_str (), prop.get_name ().c_str (), acc_s.c_str ()); + else + error ("%s: property `%s' has %s access and cannot be obtained in this context", + from.c_str (), prop.get_name ().c_str (), acc_s.c_str ()); +} + +static std::string +get_base_name (const std::string& nm) +{ + std::string::size_type pos = nm.find_last_of ('.'); + + if (pos != std::string::npos) + return nm.substr (pos + 1); + + return nm; +} + +static void +make_function_of_class (const std::string& class_name, + const octave_value& fcn) +{ + octave_function *of = fcn.function_value (); + + if (! error_state) + { + of->stash_dispatch_class (class_name); + + octave_user_function *uf = of->user_function_value (true); + + if (! error_state && uf) + { + if (get_base_name (class_name) == uf->name ()) + { + uf->mark_as_class_constructor (); + uf->mark_as_classdef_constructor (); + } + else + uf->mark_as_class_method (); + } + } +} + +static void +make_function_of_class (const cdef_class& cls, const octave_value& fcn) +{ + make_function_of_class (cls.get_name (), fcn); +} + +static octave_value +make_fcn_handle (octave_builtin::fcn ff, const std::string& nm) +{ + octave_value fcn (new octave_builtin (ff, nm)); + + octave_value fcn_handle (new octave_fcn_handle (fcn, nm)); + + return fcn_handle; +} + +static octave_value +make_fcn_handle (const octave_value& fcn, const std::string& nm) +{ + octave_value retval; + + if (fcn.is_defined ()) + retval = octave_value (new octave_fcn_handle (fcn, nm)); + + return retval; +} + +inline octave_value_list +execute_ov (octave_value val, const octave_value_list& args, int nargout) +{ + std::list idx (1, args); + + std::string type ("("); + + return val.subsref (type, idx, nargout); +} + +static cdef_class +lookup_class (const std::string& name, bool error_if_not_found = true, + bool load_if_not_found = true) +{ + return cdef_manager::find_class (name, error_if_not_found, + load_if_not_found); +} + +static cdef_class +lookup_class (const cdef_class& cls) +{ + // FIXME: placeholder for the time being, the purpose + // is to centralized any class update activity here. + + return cls; +} + +static cdef_class +lookup_class (const octave_value& ov) +{ + if (ov.is_string()) + return lookup_class (ov.string_value ()); + else + { + cdef_class cls (to_cdef (ov)); + + if (! error_state) + return lookup_class (cls); + } + + return cdef_class (); +} + +static std::list +lookup_classes (const Cell& cls_list) +{ + std::list retval; + + for (int i = 0; i < cls_list.numel (); i++) + { + cdef_class c = lookup_class (cls_list(i)); + + if (! error_state) + retval.push_back (c); + else + { + retval.clear (); + break; + } + } + + return retval; +} + +static octave_value +to_ov (const std::list& class_list) +{ + Cell cls (class_list.size (), 1); + int i = 0; + + for (std::list::const_iterator it = class_list.begin (); + it != class_list.end (); ++it, ++i) + cls(i) = to_ov (*it); + + return octave_value (cls); +} + +static bool +is_superclass (const cdef_class& clsa, const cdef_class& clsb, + bool allow_equal = true, int max_depth = -1) +{ + bool retval = false; + + if (allow_equal && clsa == clsb) + retval = true; + else if (max_depth != 0) + { + Cell c = clsb.get ("SuperClasses").cell_value (); + + for (int i = 0; ! error_state && ! retval && i < c.numel (); i++) + { + cdef_class cls = lookup_class (c(i)); + + if (! error_state) + retval = is_superclass (clsa, cls, true, + max_depth < 0 ? max_depth : max_depth-1); + } + } + + return retval; +} + +inline bool +is_strict_superclass (const cdef_class& clsa, const cdef_class& clsb) +{ return is_superclass (clsa, clsb, false); } + +inline bool +is_direct_superclass (const cdef_class& clsa, const cdef_class& clsb) +{ return is_superclass (clsa, clsb, false, 1); } + +static octave_value_list +class_get_properties (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval; + + if (args.length () == 1 && args(0).type_name () == "object") + { + cdef_class cls (to_cdef (args(0))); + + retval(0) = cls.get_properties (); + } + + return retval; +} + +static cdef_class +get_class_context (std::string& name, bool& in_constructor) +{ + cdef_class cls; + + octave_function* fcn = octave_call_stack::current (); + + in_constructor = false; + + if (fcn && + (fcn->is_class_method () + || fcn->is_classdef_constructor () + || fcn->is_anonymous_function_of_class () + || (fcn->is_private_function () + && ! fcn->dispatch_class ().empty ()))) + { + cls = lookup_class (fcn->dispatch_class ()); + if (! error_state) + { + name = fcn->name (); + in_constructor = fcn->is_classdef_constructor (); + } + } + + return cls; +} + +inline cdef_class +get_class_context (void) +{ + std::string dummy_string; + bool dummy_bool; + + return get_class_context (dummy_string, dummy_bool); +} + +static bool +check_access (const cdef_class& cls, const octave_value& acc) +{ + if (acc.is_string ()) + { + std::string acc_s = acc.string_value (); + + if (acc_s == "public") + return true; + + cdef_class ctx = get_class_context (); + + // The access is private or protected, this requires a + // valid class context. + + if (! error_state && ctx.ok ()) + { + if (acc_s == "private") + return (ctx == cls); + else if (acc_s == "protected") + return is_superclass (cls, ctx); + else + panic_impossible (); + } + } + else if (acc.is_cell ()) + { + Cell acc_c = acc.cell_value (); + + cdef_class ctx = get_class_context (); + + // At this point, a class context is always required. + + if (! error_state && ctx.ok ()) + { + if (ctx == cls) + return true; + + for (int i = 0; ! error_state && i < acc.numel (); i++) + { + cdef_class acc_cls (to_cdef (acc_c(i))); + + if (! error_state) + { + if (is_superclass (acc_cls, ctx)) + return true; + } + } + } + } + else + error ("invalid property/method access in class `%s'", + cls.get_name ().c_str ()); + + return false; +} + +bool +is_method_executing (const octave_value& ov, const cdef_object& obj) +{ + octave_function* stack_fcn = octave_call_stack::current (); + + octave_function* method_fcn = ov.function_value (true); + + // Does the top of the call stack match our target function? + + if (stack_fcn && stack_fcn == method_fcn) + { + octave_user_function* uf = method_fcn->user_function_value (true); + + // We can only check the context object for user-function (not builtin), + // where we have access to the parameters (arguments and return values). + // That's ok as there's no need to call this function for builtin + // methods. + + if (uf) + { + // At this point, the method is executing, but we still need to + // check the context object for which the method is executing. For + // methods, it's the first argument of the function; for ctors, it + // is the first return value. + + tree_parameter_list* pl = uf->is_classdef_constructor () + ? uf->return_list () : uf->parameter_list (); + + if (pl && pl->size () > 0) + { + octave_value arg0 = pl->front ()->lvalue ().value (); + + if (arg0.is_defined () && arg0.type_name () == "object") + { + cdef_object arg0_obj = to_cdef (arg0); + + return obj.is (arg0_obj); + } + } + } + } + + return false; +} + +static octave_value_list +class_get_methods (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval; + + if (args.length () == 1 && args(0).type_name () == "object") + { + cdef_class cls (to_cdef (args(0))); + + retval(0) = cls.get_methods (); + } + + return retval; +} + +static octave_value_list +class_get_superclasses (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval; + + if (args.length () == 1 && args(0).type_name () == "object" + && args(0).class_name () == "meta.class") + { + cdef_class cls (to_cdef (args(0))); + + Cell classes = cls.get ("SuperClasses").cell_value (); + + retval(0) = to_ov (lookup_classes (classes)); + } + + return retval; +} + +static octave_value_list +class_get_inferiorclasses (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval; + + if (args.length () == 1 && args(0).type_name () == "object" + && args(0).class_name () == "meta.class") + { + cdef_class cls (to_cdef (args(0))); + + Cell classes = cls.get ("InferiorClasses").cell_value (); + + retval(0) = to_ov (lookup_classes (classes)); + } + + return retval; +} + +static octave_value_list +class_fromName (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval; + + if (args.length () == 1) + { + std::string name = args(0).string_value (); + + if (! error_state) + retval(0) = to_ov (lookup_class (name)); + else + error ("fromName: invalid class name, expected a string value"); + } + else + error ("fromName: invalid number of parameters"); + + return retval; +} + +static octave_value_list +class_fevalStatic (const octave_value_list& args, int nargout) +{ + octave_value_list retval; + + if (args.length () > 1 && args(0).type_name () == "object") + { + cdef_class cls (to_cdef (args(0))); + + if (! error_state) + { + std::string meth_name = args(1).string_value (); + + if (! error_state) + { + cdef_method meth = cls.find_method (meth_name); + + if (meth.ok ()) + { + if (meth.is_static ()) + retval = meth.execute (args.splice (0, 2), nargout, + true, "fevalStatic"); + else + error ("fevalStatic: method `%s' is not static", + meth_name.c_str ()); + } + else + error ("fevalStatic: method not found: %s", + meth_name.c_str ()); + } + else + error ("fevalStatic: invalid method name, expected a string value"); + } + error ("fevalStatic: invalid object, expected a meta.class object"); + } + else + error ("fevalStatic: invalid arguments"); + + return retval; +} + +static octave_value_list +class_getConstant (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval; + + if (args.length () == 2 && args(0).type_name () == "object" + && args(0).class_name () == "meta.class") + { + cdef_class cls = to_cdef (args(0)); + + if (! error_state) + { + std::string prop_name = args(1).string_value (); + + if (! error_state) + { + cdef_property prop = cls.find_property (prop_name); + + if (prop.ok ()) + { + if (prop.is_constant ()) + retval(0) = prop.get_value (true, "getConstant"); + else + error ("getConstant: property `%s' is not constant", + prop_name.c_str ()); + } + else + error ("getConstant: property not found: %s", + prop_name.c_str ()); + } + else + error ("getConstant: invalid property name, expected a string value"); + } + else + error ("getConstant: invalid object, expected a meta.class object"); + } + else + error ("getConstant: invalid arguments"); + + return retval; +} + +#define META_CLASS_CMP(OP, CLSA, CLSB, FUN) \ +static octave_value_list \ +class_ ## OP (const octave_value_list& args, int /* nargout */) \ +{ \ + octave_value_list retval; \ +\ + if (args.length () == 2 \ + && args(0).type_name () == "object" && args(1).type_name () == "object" \ + && args(0).class_name () == "meta.class" && args(1).class_name () == "meta.class") \ + { \ + cdef_class clsa = to_cdef (args(0)); \ +\ + cdef_class clsb = to_cdef (args(1)); \ +\ + if (! error_state) \ + retval(0) = FUN (CLSA, CLSB); \ + else \ + error (#OP ": invalid objects, expected meta.class objects"); \ + } \ + else \ + error (#OP ": invalid arguments"); \ +\ + return retval; \ +} + +META_CLASS_CMP (lt, clsb, clsa, is_strict_superclass) +META_CLASS_CMP (le, clsb, clsa, is_superclass) +META_CLASS_CMP (gt, clsa, clsb, is_strict_superclass) +META_CLASS_CMP (ge, clsa, clsb, is_superclass) +META_CLASS_CMP (eq, clsa, clsb, operator==) +META_CLASS_CMP (ne, clsa, clsb, operator!=) + +octave_value_list +property_get_defaultvalue (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval; + + if (args.length () == 1 && args(0).type_name () == "object") + { + cdef_property prop (to_cdef (args(0))); + + retval(0) = prop.get ("DefaultValue"); + + if (! retval(0).is_defined ()) + error_with_id ("Octave:class:NotDefaultDefined", + "no default value for property `%s'", + prop.get_name ().c_str ()); + } + + return retval; +} + +static octave_value_list +handle_delete (const octave_value_list& /* args */, int /* nargout */) +{ + octave_value_list retval; + + // FIXME: implement this + + return retval; +} + +static cdef_class +make_class (const std::string& name, + const std::list& super_list = std::list ()) +{ + cdef_class cls (name, super_list); + + cls.set_class (cdef_class::meta_class ()); + cls.put ("Abstract", false); + cls.put ("ConstructOnLoad", false); + cls.put ("ContainingPackage", Matrix ()); + cls.put ("Description", std::string ()); + cls.put ("DetailedDescription", std::string ()); + cls.put ("Events", Cell ()); + cls.put ("Hidden", false); + cls.put ("InferiorClasses", Cell ()); + cls.put ("Methods", Cell ()); + cls.put ("Properties", Cell ()); + cls.put ("Sealed", false); + + if (name == "handle") + { + cls.put ("HandleCompatible", true); + cls.mark_as_handle_class (); + } + else if (super_list.empty ()) + { + cls.put ("HandleCompatible", false); + } + else + { + bool all_handle_compatible = true; + bool has_handle_class = false; + + for (std::list::const_iterator it = super_list.begin (); + it != super_list.end (); ++it) + { + all_handle_compatible = all_handle_compatible && it->get ("HandleCompatible").bool_value (); + has_handle_class = has_handle_class || it->is_handle_class (); + } + + if (has_handle_class && ! all_handle_compatible) + ::error ("%s: cannot mix handle and non-HandleCompatible classes", + name.c_str ()); + else + { + cls.put ("HandleCompatible", all_handle_compatible); + if (has_handle_class) + cls.mark_as_handle_class (); + } + } + + if (error_state) + return cdef_class (); + + if (! name.empty ()) + cdef_manager::register_class (cls); + + return cls; +} + +static cdef_class +make_class (const std::string& name, const cdef_class& super) +{ + return make_class (name, std::list (1, super)); +} + +static cdef_class +make_meta_class (const std::string& name, const cdef_class& super) +{ + cdef_class cls = make_class (name, super); + + cls.put ("Sealed", true); + cls.mark_as_meta_class (); + + return cls; +} + +static cdef_property +make_property (const cdef_class& cls, const std::string& name, + const octave_value& get_method = Matrix (), + const std::string& get_access = "public", + const octave_value& set_method = Matrix (), + const std::string& set_access = "public") +{ + cdef_property prop (name); + + prop.set_class (cdef_class::meta_property ()); + prop.put ("Description", std::string ()); + prop.put ("DetailedDescription", std::string ()); + prop.put ("Abstract", false); + prop.put ("Constant", false); + prop.put ("GetAccess", get_access); + prop.put ("SetAccess", set_access); + prop.put ("Dependent", false); + prop.put ("Transient", false); + prop.put ("Hidden", false); + prop.put ("GetObservable", false); + prop.put ("SetObservable", false); + prop.put ("GetMethod", get_method); + prop.put ("SetMethod", set_method); + prop.put ("DefiningClass", to_ov (cls)); + prop.put ("DefaultValue", octave_value ()); + prop.put ("HasDefault", false); + + std::string class_name = cls.get_name (); + + if (! get_method.is_empty ()) + make_function_of_class (class_name, get_method); + if (! set_method.is_empty ()) + make_function_of_class (class_name, set_method); + + return prop; +} + +inline cdef_property +make_attribute (const cdef_class& cls, const std::string& name) +{ + return make_property (cls, name, Matrix (), "public", Matrix (), "private"); +} + +static cdef_method +make_method (const cdef_class& cls, const std::string& name, + const octave_value& fcn,const std::string& m_access = "public", + bool is_static = false) +{ + cdef_method meth (name); + + meth.set_class (cdef_class::meta_method ()); + meth.put ("Abstract", false); + meth.put ("Access", m_access); + meth.put ("DefiningClass", to_ov (cls)); + meth.put ("Description", std::string ()); + meth.put ("DetailedDescription", std::string ()); + meth.put ("Hidden", false); + meth.put ("Sealed", true); + meth.put ("Static", is_static); + + if (fcn.is_defined ()) + make_function_of_class (cls, fcn); + + meth.set_function (fcn); + + return meth; +} + +inline cdef_method +make_method (const cdef_class& cls, const std::string& name, + octave_builtin::fcn ff, const std::string& m_access = "public", + bool is_static = false) +{ + octave_value fcn (new octave_builtin (ff, name)); + + return make_method (cls, name, fcn, m_access, is_static); +} + +static cdef_package +make_package (const std::string& nm, + const std::string& parent = std::string ()) +{ + cdef_package pack (nm); + + pack.set_class (cdef_class::meta_package ()); + if (parent.empty ()) + pack.put ("ContainingPackage", Matrix ()); + else + pack.put ("ContainingPackage", to_ov (cdef_manager::find_package (parent))); + + if (! nm.empty ()) + cdef_manager::register_package (pack); + + return pack; +} + +//---------------------------------------------------------------------------- + +DEFINE_OCTAVE_ALLOCATOR (octave_classdef); + +int octave_classdef::t_id (-1); + +const std::string octave_classdef::t_name ("object"); + +void +octave_classdef::register_type (void) +{ + t_id = octave_value_typeinfo::register_type + (octave_classdef::t_name, "", octave_value (new octave_classdef ())); +} + +octave_value_list +octave_classdef::subsref (const std::string& type, + const std::list& idx, + int nargout) +{ + size_t skip = 0; + octave_value_list retval; + + // FIXME: should check "subsref" method first + + retval = object.subsref (type, idx, nargout, skip, cdef_class ()); + + if (! error_state) + { + if (type.length () > skip && idx.size () > skip) + retval = retval(0).next_subsref (nargout, type, idx, skip); + } + + return retval; +} + +octave_value +octave_classdef::subsref (const std::string& type, + const std::list& idx, + bool auto_add) +{ + size_t skip = 0; + octave_value_list retval; + + // FIXME: should check "subsref" method first + // ? not sure this still applied with auto_add version of subsref + + retval = object.subsref (type, idx, 1, skip, cdef_class (), auto_add); + + if (! error_state) + { + if (type.length () > skip && idx.size () > skip) + retval = retval(0).next_subsref (1, type, idx, skip); + } + + return retval.length () > 0 ? retval(0) : octave_value (); +} + +octave_value +octave_classdef::subsasgn (const std::string& type, + const std::list& idx, + const octave_value& rhs) +{ + // FIXME: should check "subsasgn" method first + + return object.subsasgn (type, idx, rhs); +} + +octave_value +octave_classdef::undef_subsasgn (const std::string& type, + const std::list& idx, + const octave_value& rhs) +{ + if (type.length () == 1 && type[0] == '(') + { + object = object.make_array (); + + if (! error_state) + return subsasgn (type, idx, rhs); + } + else + return octave_base_value::undef_subsasgn (type, idx, rhs); + + return octave_value (); +} + +//---------------------------------------------------------------------------- + +class octave_classdef_meta : public octave_function +{ +public: + octave_classdef_meta (const cdef_meta_object& obj) + : object (obj) { } + + ~octave_classdef_meta (void) + { object.meta_release (); } + + octave_function* function_value (bool = false) { return this; } + + octave_value_list + subsref (const std::string& type, + const std::list& idx, + int nargout) + { return object.meta_subsref (type, idx, nargout); } + + octave_value + subsref (const std::string& type, + const std::list& idx) + { + octave_value_list retval; + + retval = subsref (type, idx, 1); + + return (retval.length () > 0 ? retval(0) : octave_value ()); + } + + octave_value_list + do_multi_index_op (int nargout, const octave_value_list& idx) + { + // Emulate ()-type meta subsref + + std::list l (1, idx); + std::string type ("("); + + return subsref (type, l, nargout); + } + + bool is_postfix_index_handled (char type) const + { return object.meta_is_postfix_index_handled (type); } + +private: + cdef_meta_object object; +}; + +//---------------------------------------------------------------------------- + +class octave_classdef_superclass_ref : public octave_function +{ +public: + octave_classdef_superclass_ref (const octave_value_list& a) + : octave_function (), args (a) { } + + ~octave_classdef_superclass_ref (void) { } + + octave_value_list + subsref (const std::string& type, + const std::list& idx, + int nargout) + { + size_t skip = 0; + octave_value_list retval; + + switch (type[0]) + { + case '(': + skip = 1; + retval = do_multi_index_op (type.length () > 1 ? 1 : nargout, + idx.front ()); + break; + default: + retval = do_multi_index_op (1, octave_value_list ()); + break; + } + + if (! error_state) + { + if (type.length () > skip && idx.size () > skip + && retval.length () > 0) + retval = retval(0).next_subsref (nargout, type, idx, skip); + } + + return retval; + } + + octave_value + subsref (const std::string& type, + const std::list& idx) + { + octave_value_list retval; + + retval = subsref (type, idx, 1); + + return (retval.length () > 0 ? retval(0) : octave_value ()); + } + + octave_value_list + do_multi_index_op (int nargout, const octave_value_list& idx) + { + octave_value_list retval; + + std::string meth_name; + bool in_constructor; + cdef_class ctx; + + ctx = get_class_context (meth_name, in_constructor); + + if (! error_state && ctx.ok ()) + { + std::string mname = args(0).string_value (); + std::string pname = args(1).string_value (); + std::string cname = args(2).string_value (); + + std::string cls_name = (pname.empty () ? + cname : pname + "." + cname); + cdef_class cls = lookup_class (cls_name); + + if (! error_state) + { + if (in_constructor) + { + if (is_direct_superclass (cls, ctx)) + { + if (is_constructed_object (mname)) + { + octave_value& sym = symbol_table::varref (mname); + + cls.run_constructor (to_cdef_ref (sym), idx); + + retval(0) = sym; + } + else + ::error ("cannot call superclass constructor with " + "variable `%s'", mname.c_str ()); + } + else + ::error ("`%s' is not a direct superclass of `%s'", + cls_name.c_str (), ctx.get_name ().c_str ()); + } + else + { + if (mname == meth_name) + { + if (is_strict_superclass (cls, ctx)) + { + // I see 2 possible implementations here: + // 1) use cdef_object::subsref with a different class + // context; this avoids duplicating code, but + // assumes the object is always the first argument + // 2) lookup the method manually and call + // cdef_method::execute; this duplicates part of + // logic in cdef_object::subsref, but avoid the + // assumption of 1) + // Not being sure about the assumption of 1), I + // go with option 2) for the time being. + + cdef_method meth = cls.find_method (meth_name, false); + + if (meth.ok ()) + retval = meth.execute (idx, nargout, true, + meth_name); + else + ::error ("no method `%s' found in superclass `%s'", + meth_name.c_str (), cls_name.c_str ()); + } + else + ::error ("`%s' is not a superclass of `%s'", + cls_name.c_str (), ctx.get_name ().c_str ()); + } + else + ::error ("method name mismatch (`%s' != `%s')", + mname.c_str (), meth_name.c_str ()); + } + } + } + else if (! error_state) + ::error ("superclass calls can only occur in methods or constructors"); + + return retval; + } + +private: + bool is_constructed_object (const std::string nm) + { + octave_function *of = octave_call_stack::current (); + + if (of->is_classdef_constructor ()) + { + octave_user_function *uf = of->user_function_value (true); + + if (uf) + { + tree_parameter_list *ret_list = uf->return_list (); + + if (ret_list && ret_list->length () == 1) + return (ret_list->front ()->name () == nm); + } + } + + return false; + } + +private: + octave_value_list args; +}; + +//---------------------------------------------------------------------------- + +string_vector +cdef_object_rep::map_keys (void) const +{ + cdef_class cls = get_class (); + + if (cls.ok ()) + return cls.get_names (); + + return string_vector (); +} + +octave_value_list +cdef_object_scalar::subsref (const std::string& type, + const std::list& idx, + int nargout, size_t& skip, + const cdef_class& context, bool auto_add) +{ + skip = 0; + + cdef_class cls = (context.ok () ? context : get_class ()); + + octave_value_list retval; + + if (! cls.ok ()) + return retval; + + switch (type[0]) + { + case '.': + { + std::string name = (idx.front ())(0).string_value (); + + cdef_method meth = cls.find_method (name); + + if (meth.ok ()) + { + int _nargout = (type.length () > 2 ? 1 : nargout); + + octave_value_list args; + + skip = 1; + + if (type.length () > 1 && type[1] == '(') + { + std::list::const_iterator it = idx.begin (); + + args = *++it; + + skip++; + } + + if (meth.is_static ()) + retval = meth.execute (args, _nargout, true, "subsref"); + else + { + refcount++; + retval = meth.execute (cdef_object (this), args, _nargout, + true, "subsref"); + } + } + + if (skip == 0 && ! error_state) + { + cdef_property prop = cls.find_property (name); + + if (prop.ok ()) + { + if (prop.is_constant ()) + retval(0) = prop.get_value (true, "subsref"); + else + { + refcount++; + retval(0) = prop.get_value (cdef_object (this), + true, "subsref"); + } + + skip = 1; + } + else + error ("subsref: unknown method or property: %s", name.c_str ()); + } + break; + } + + case '(': + { + refcount++; + + cdef_object this_obj (this); + + Array arr (dim_vector (1, 1), this_obj); + + cdef_object new_obj = cdef_object (new cdef_object_array (arr)); + + new_obj.set_class (get_class ()); + + retval = new_obj.subsref (type, idx, nargout, skip, cls, auto_add); + } + break; + + default: + error ("object cannot be indexed with `%c'", type[0]); + break; + } + + return retval; +} + +octave_value +cdef_object_scalar::subsasgn (const std::string& type, + const std::list& idx, + const octave_value& rhs) +{ + octave_value retval; + + cdef_class cls = get_class (); + + switch (type[0]) + { + case '.': + { + std::string name = (idx.front ())(0).string_value (); + + if (! error_state) + { + cdef_property prop = cls.find_property (name); + + if (prop.ok ()) + { + if (prop.is_constant ()) + error ("subsasgn: cannot assign constant property: %s", + name.c_str ()); + else + { + refcount++; + + cdef_object obj (this); + + if (type.length () == 1) + { + prop.set_value (obj, rhs, true, "subsasgn"); + + if (! error_state) + retval = to_ov (obj); + } + else + { + octave_value val = + prop.get_value (obj, true, "subsasgn"); + + if (! error_state) + { + std::list args (idx); + + args.erase (args.begin ()); + + val = val.assign (octave_value::op_asn_eq, + type.substr (1), args, rhs); + + if (! error_state) + { + if (val.class_name () != "object" + || ! to_cdef (val).is_handle_object ()) + prop.set_value (obj, val, true, "subsasgn"); + + if (! error_state) + retval = to_ov (obj); + } + } + } + } + } + else + error ("subsasgn: unknown property: %s", name.c_str ()); + } + } + break; + + case '(': + { + refcount++; + + cdef_object this_obj (this); + + Array arr (dim_vector (1, 1), this_obj); + + cdef_object new_obj = cdef_object (new cdef_object_array (arr)); + + new_obj.set_class (get_class ()); + + octave_value tmp = new_obj.subsasgn (type, idx, rhs); + + if (! error_state) + retval = tmp; + } + break; + + default: + error ("subsasgn: object cannot be index with `%c'", type[0]); + break; + } + + return retval; +} + +void +cdef_object_scalar::mark_for_construction (const cdef_class& cls) +{ + std::string cls_name = cls.get_name (); + + Cell supcls = cls.get ("SuperClasses").cell_value (); + + if (! error_state) + { + std::list supcls_list = lookup_classes (supcls); + + if (! error_state) + ctor_list[cls] = supcls_list; + } +} + +octave_value_list +cdef_object_array::subsref (const std::string& type, + const std::list& idx, + int /* nargout */, size_t& skip, + const cdef_class& /* context */, bool auto_add) +{ + octave_value_list retval; + + skip = 1; + + switch (type[0]) + { + case '(': + { + const octave_value_list& ival = idx.front (); + bool is_scalar = true; + Array iv (dim_vector (1, ival.length ())); + + for (int i = 0; ! error_state && i < ival.length (); i++) + { + iv(i) = ival(i).index_vector (); + if (! error_state) + is_scalar = is_scalar && iv(i).is_scalar (); + } + + if (! error_state) + { + Array ires = array.index (iv, auto_add); + + if (! error_state) + { + // If resizing is enabled (auto_add = true), it's possible + // indexing was out-of-bound and the result array contains + // invalid cdef_objects. + + if (auto_add) + fill_empty_values (ires); + + if (is_scalar) + retval(0) = to_ov (ires(0)); + else + { + cdef_object array_obj (new cdef_object_array (ires)); + + array_obj.set_class (get_class ()); + + retval(0) = to_ov (array_obj); + } + } + } + } + break; + + case '.': + if (type.size () == 1 && idx.size () == 1) + { + Cell c (dims ()); + + octave_idx_type n = array.numel (); + + // dummy variables + size_t dummy_skip; + cdef_class dummy_cls; + + for (octave_idx_type i = 0; i < n; i++) + { + octave_value_list r = array(i).subsref (type, idx, 1, dummy_skip, + dummy_cls); + + if (! error_state) + { + if (r.length () > 0) + c(i) = r(0); + } + else + break; + } + + if (! error_state) + retval(0) = octave_value (c, true); + + break; + } + // fall through "default" + + default: + ::error ("can't perform indexing operation on array of %s objects", + class_name ().c_str ()); + break; + } + + return retval; +} + +octave_value +cdef_object_array::subsasgn (const std::string& type, + const std::list& idx, + const octave_value& rhs) +{ + octave_value retval; + + switch (type[0]) + { + case '(': + if (type.length () == 1) + { + cdef_object rhs_obj = to_cdef (rhs); + + if (! error_state) + { + if (rhs_obj.get_class () == get_class ()) + { + const octave_value_list& ival = idx.front (); + bool is_scalar = true; + Array iv (dim_vector (1, ival.length ())); + + for (int i = 0; ! error_state && i < ival.length (); i++) + { + iv(i) = ival(i).index_vector (); + if (! error_state) + is_scalar = is_scalar && iv(i).is_scalar (); + } + + if (! error_state) + { + Array rhs_mat; + + if (! rhs_obj.is_array ()) + { + rhs_mat = Array (dim_vector (1, 1)); + rhs_mat(0) = rhs_obj; + } + else + rhs_mat = rhs_obj.array_value (); + + if (! error_state) + { + octave_idx_type n = array.numel (); + + array.assign (iv, rhs_mat, cdef_object ()); + + if (! error_state) + { + if (array.numel () > n) + fill_empty_values (); + + if (! error_state) + { + refcount++; + retval = to_ov (cdef_object (this)); + } + } + } + } + } + else + ::error ("can't assign %s object into array of %s objects.", + rhs_obj.class_name ().c_str (), + class_name ().c_str ()); + } + } + else + { + const octave_value_list& ival = idx.front (); + + bool is_scalar = true; + + Array iv (dim_vector (1, ival.length ())); + + for (int i = 0; ! error_state && i < ival.length (); i++) + { + iv(i) = ival(i).index_vector (); + + if (! error_state) + { + is_scalar = is_scalar && iv(i).is_scalar (); + + if (! is_scalar) + error ("subsasgn: invalid indexing for object array " + "assignment, the index must reference a single " + "object in the array."); + } + } + + if (! error_state) + { + Array a = array.index (iv, true); + + if (a.numel () != 1) + error ("subsasgn: invalid indexing for object array " + "assignment"); + + if (! error_state) + { + cdef_object obj = a(0); + + int ignore_copies = 0; + + // If the object in 'a' is not valid, this means the index + // was out-of-bound and we need to create a new object. + + if (! obj.ok ()) + obj = get_class ().construct_object (octave_value_list ()); + else + // Optimize the subsasgn call to come. There are 2 copies + // that we can safely ignore: + // - 1 in "array" + // - 1 in "a" + ignore_copies = 2; + + std::list next_idx (idx); + + next_idx.erase (next_idx.begin ()); + + octave_value tmp = obj.subsasgn (type.substr (1), next_idx, + rhs, ignore_copies); + + if (! error_state) + { + cdef_object robj = to_cdef (tmp); + + if (robj.ok () + && ! robj.is_array () + && robj.get_class () == get_class ()) + { + // Small optimization, when dealing with handle + // objects, we don't need to re-assign the result + // of subsasgn back into the array. + + if (! robj.is (a(0))) + { + Array rhs_a (dim_vector (1, 1), + robj); + + octave_idx_type n = array.numel (); + + array.assign (iv, rhs_a); + + if (array.numel () > n) + fill_empty_values (); + } + + refcount++; + + retval = to_ov (cdef_object (this)); + } + else + error ("subasgn: invalid assignment into array of %s " + "objects", class_name ().c_str ()); + } + } + } + } + break; + + default: + ::error ("can't perform indexing operation on array of %s objects", + class_name ().c_str ()); + break; + } + + return retval; +} + +void +cdef_object_array::fill_empty_values (Array& arr) +{ + cdef_class cls = get_class (); + + if (! error_state) + { + cdef_object obj; + + int n = arr.numel (); + + for (int i = 0; ! error_state && i < n; i++) + { + if (! arr.xelem (i).ok ()) + { + if (! obj.ok ()) + { + obj = cls.construct_object (octave_value_list ()); + + if (! error_state) + arr.xelem (i) = obj; + } + else + arr.xelem (i) = obj.copy (); + } + } + } +} + +bool cdef_object_scalar::is_constructed_for (const cdef_class& cls) const +{ + return (is_constructed () + || ctor_list.find (cls) == ctor_list.end ()); +} + +bool cdef_object_scalar::is_partially_constructed_for (const cdef_class& cls) const +{ + std::map< cdef_class, std::list >::const_iterator it; + + if (is_constructed ()) + return true; + else if ((it = ctor_list.find (cls)) == ctor_list.end () + || it->second.empty ()) + return true; + + for (std::list::const_iterator lit = it->second.begin (); + lit != it->second.end (); ++lit) + if (! is_constructed_for (*lit)) + return false; + + return true; +} + +handle_cdef_object::~handle_cdef_object (void) +{ + gnulib::printf ("deleting %s object (handle)\n", + get_class ().get_name ().c_str ()); +} + +value_cdef_object::~value_cdef_object (void) +{ + gnulib::printf ("deleting %s object (value)\n", + get_class ().get_name ().c_str ()); +} + +cdef_class::cdef_class_rep::cdef_class_rep (const std::list& superclasses) + : cdef_meta_object_rep (), member_count (0), handle_class (false), + object_count (0), meta (false) +{ + put ("SuperClasses", to_ov (superclasses)); + implicit_ctor_list = superclasses; +} + +cdef_method +cdef_class::cdef_class_rep::find_method (const std::string& nm, bool local) +{ + method_iterator it = method_map.find (nm); + + if (it == method_map.end ()) + { + // FIXME: look into class directory + } + else + { + cdef_method& meth = it->second; + + // FIXME: check if method reload needed + + if (meth.ok ()) + return meth; + } + + if (! local) + { + // Look into superclasses + + Cell super_classes = get ("SuperClasses").cell_value (); + + for (int i = 0; i < super_classes.numel (); i++) + { + cdef_class cls = lookup_class (super_classes(i)); + + if (! error_state) + { + cdef_method meth = cls.find_method (nm); + + if (meth.ok ()) + return meth; + } + } + } + + return cdef_method (); +} + +class ctor_analyzer : public tree_walker +{ +public: + ctor_analyzer (const std::string& ctor, const std::string& obj) + : tree_walker (), who (ctor), obj_name (obj) { } + + void visit_statement_list (tree_statement_list& t) + { + for (tree_statement_list::const_iterator it = t.begin (); + ! error_state && it != t.end (); ++it) + (*it)->accept (*this); + } + + void visit_statement (tree_statement& t) + { + if (t.is_expression ()) + t.expression ()->accept (*this); + } + + void visit_simple_assignment (tree_simple_assignment& t) + { + t.right_hand_side ()->accept (*this); + } + + void visit_multi_assignment (tree_multi_assignment& t) + { + t.right_hand_side ()->accept (*this); + } + + void visit_index_expression (tree_index_expression& t) + { + t.expression ()->accept (*this); + } + + void visit_funcall (tree_funcall& t) + { + octave_value fcn = t.function (); + + if (fcn.is_function ()) + { + octave_function *of = fcn.function_value (true); + + if (of) + { + if (of->name () == "__superclass_reference__") + { + octave_value_list args = t.arguments (); + + if (args(0).string_value () == obj_name) + { + std::string package_name = args(1).string_value (); + std::string class_name = args(2).string_value (); + + std::string ctor_name = (package_name.empty () + ? class_name + : package_name + "." + class_name); + + cdef_class cls = lookup_class (ctor_name, false); + + if (cls.ok ()) + ctor_list.push_back (cls); + } + } + } + } + } + + std::list get_constructor_list (void) const + { return ctor_list; } + + // NO-OP + void visit_anon_fcn_handle (tree_anon_fcn_handle&) { } + void visit_argument_list (tree_argument_list&) { } + void visit_binary_expression (tree_binary_expression&) { } + void visit_break_command (tree_break_command&) { } + void visit_colon_expression (tree_colon_expression&) { } + void visit_continue_command (tree_continue_command&) { } + void visit_global_command (tree_global_command&) { } + void visit_persistent_command (tree_persistent_command&) { } + void visit_decl_elt (tree_decl_elt&) { } + void visit_decl_init_list (tree_decl_init_list&) { } + void visit_simple_for_command (tree_simple_for_command&) { } + void visit_complex_for_command (tree_complex_for_command&) { } + void visit_octave_user_script (octave_user_script&) { } + void visit_octave_user_function (octave_user_function&) { } + void visit_function_def (tree_function_def&) { } + void visit_identifier (tree_identifier&) { } + void visit_if_clause (tree_if_clause&) { } + void visit_if_command (tree_if_command&) { } + void visit_if_command_list (tree_if_command_list&) { } + void visit_switch_case (tree_switch_case&) { } + void visit_switch_case_list (tree_switch_case_list&) { } + void visit_switch_command (tree_switch_command&) { } + void visit_matrix (tree_matrix&) { } + void visit_cell (tree_cell&) { } + void visit_no_op_command (tree_no_op_command&) { } + void visit_constant (tree_constant&) { } + void visit_fcn_handle (tree_fcn_handle&) { } + void visit_parameter_list (tree_parameter_list&) { } + void visit_postfix_expression (tree_postfix_expression&) { } + void visit_prefix_expression (tree_prefix_expression&) { } + void visit_return_command (tree_return_command&) { } + void visit_return_list (tree_return_list&) { } + void visit_try_catch_command (tree_try_catch_command&) { } + void visit_unwind_protect_command (tree_unwind_protect_command&) { } + void visit_while_command (tree_while_command&) { } + void visit_do_until_command (tree_do_until_command&) { } + +private: + /* The name of the constructor being analyzed */ + std::string who; + + /* The name of the first output argument of the constructor */ + std::string obj_name; + + /* The list of superclass constructors that are explicitly called */ + std::list ctor_list; +}; + +void +cdef_class::cdef_class_rep::install_method (const cdef_method& meth) +{ + method_map[meth.get_name ()] = meth; + + member_count++; + + if (meth.is_constructor ()) + { + // Analyze the constructor code to determine what superclass + // constructors are called explicitly. + + octave_function *of = meth.get_function ().function_value (true); + + if (of) + { + octave_user_function *uf = of->user_function_value (true); + + if (uf) + { + tree_parameter_list *ret_list = uf->return_list (); + tree_statement_list *body = uf->body (); + + if (ret_list && ret_list->size () == 1) + { + std::string obj_name = ret_list->front ()->name (); + ctor_analyzer a (meth.get_name (), obj_name); + + body->accept (a); + if (! error_state) + { + std::list explicit_ctor_list + = a.get_constructor_list (); + + for (std::list::const_iterator it = explicit_ctor_list.begin (); + ! error_state && it != explicit_ctor_list.end (); ++it) + { + gnulib::printf ("explicit superclass constructor: %s\n", + it->get_name ().c_str ()); + implicit_ctor_list.remove (*it); + } + } + } + else + ::error ("%s: invalid constructor output arguments", + meth.get_name ().c_str ()); + } + } + } +} + +void +cdef_class::cdef_class_rep::load_all_methods (void) +{ + // FIXME: re-scan class directory +} + +Cell +cdef_class::cdef_class_rep::get_methods (void) +{ + std::map meths; + + find_methods (meths, false); + + if (! error_state) + { + Cell c (meths.size (), 1); + + int idx = 0; + + for (std::map::const_iterator it = meths.begin (); + it != meths.end (); ++it, ++idx) + c (idx, 0) = to_ov (it->second); + + return c; + } + + return Cell (); +} + +void +cdef_class::cdef_class_rep::find_methods (std::map& meths, + bool only_inherited) +{ + load_all_methods (); + + method_const_iterator it; + + for (it = method_map.begin (); it != method_map.end (); ++it) + { + if (! it->second.is_constructor ()) + { + std::string nm = it->second.get_name (); + + if (meths.find (nm) == meths.end ()) + { + if (only_inherited) + { + octave_value acc = it->second.get ("Access"); + + if (! acc.is_string () + || acc.string_value () == "private") + continue; + } + + meths[nm] = it->second; + } + } + } + + // Look into superclasses + + Cell super_classes = get ("SuperClasses").cell_value (); + + for (int i = 0; i < super_classes.numel (); i++) + { + cdef_class cls = lookup_class (super_classes(i)); + + if (! error_state) + cls.get_rep ()->find_methods (meths, true); + else + break; + } +} + +cdef_property +cdef_class::cdef_class_rep::find_property (const std::string& nm) +{ + property_iterator it = property_map.find (nm); + + if (it != property_map.end ()) + { + cdef_property& prop = it->second; + + if (prop.ok ()) + return prop; + } + + // Look into superclasses + + Cell super_classes = get ("SuperClasses").cell_value (); + + for (int i = 0; i < super_classes.numel (); i++) + { + cdef_class cls = lookup_class (super_classes(i)); + + if (! error_state) + { + cdef_property prop = cls.find_property (nm); + + if (prop.ok ()) + return prop; + } + } + + return cdef_property (); +} + +void +cdef_class::cdef_class_rep::install_property (const cdef_property& prop) +{ + property_map[prop.get_name ()] = prop; + + member_count++; +} + +Cell +cdef_class::cdef_class_rep::get_properties (void) +{ + std::map props; + + find_properties (props, false); + + if (! error_state) + { + Cell c (props.size (), 1); + + int idx = 0; + + for (std::map::const_iterator it = props.begin (); + it != props.end (); ++it, ++idx) + c (idx, 0) = to_ov (it->second); + + return c; + } + + return Cell (); +} + +void +cdef_class::cdef_class_rep::find_properties (std::map& props, + bool only_inherited) +{ + property_const_iterator it; + + for (it = property_map.begin (); ! error_state && it != property_map.end (); + ++it) + { + std::string nm = it->second.get_name (); + + if (props.find (nm) == props.end ()) + { + if (only_inherited) + { + octave_value acc = it->second.get ("GetAccess"); + + if (! acc.is_string () + || acc.string_value () == "private") + continue; + } + + props[nm] = it->second; + } + } + + // Look into superclasses + + Cell super_classes = get ("SuperClasses").cell_value (); + + for (int i = 0; ! error_state && i < super_classes.numel (); i++) + { + cdef_class cls = lookup_class (super_classes(i)); + + if (! error_state) + cls.get_rep ()->find_properties (props, true); + else + break; + } +} + +void +cdef_class::cdef_class_rep::find_names (std::set& names, + bool all) +{ + load_all_methods (); + + for (method_const_iterator it = method_map.begin (); + ! error_state && it != method_map.end(); ++it) + { + if (! it->second.is_constructor ()) + { + std::string nm = it->second.get_name (); + + if (! all) + { + octave_value acc = it->second.get ("Access"); + + if (! acc.is_string() + || acc.string_value () != "public") + continue; + } + + names.insert (nm); + } + } + + for (property_const_iterator it = property_map.begin (); + ! error_state && it != property_map.end (); ++it) + { + std::string nm = it->second.get_name (); + + if (! all) + { + octave_value acc = it->second.get ("GetAccess"); + + if (! acc.is_string() + || acc.string_value () != "public") + continue; + } + + names.insert (nm); + } + + // Look into superclasses + + Cell super_classes = get ("SuperClasses").cell_value (); + + for (int i = 0; ! error_state && i < super_classes.numel (); i++) + { + cdef_class cls = lookup_class (super_classes(i)); + + if (! error_state) + cls.get_rep ()->find_names (names, all); + else + break; + } +} + +string_vector +cdef_class::cdef_class_rep::get_names (void) +{ + std::set names; + + find_names (names, false); + + if (! error_state) + { + string_vector v (names.size ()); + + int idx = 0; + for (std::set::const_iterator it = names.begin (); + it != names.end (); ++it, ++idx) + v[idx] = *it; + + return v.sort (true); + } + + return string_vector (); +} + +void +cdef_class::cdef_class_rep::delete_object (cdef_object obj) +{ + method_iterator it = method_map.find ("delete"); + + if (it != method_map.end ()) + { + cdef_class cls = obj.get_class (); + + obj.set_class (wrap ()); + + it->second.execute (obj, octave_value_list (), 0, false); + + obj.set_class (cls); + } + + // FIXME: should we destroy corresponding properties here? + + // Call "delete" in super classes + + Cell super_classes = get ("SuperClasses").cell_value (); + + for (int i = 0; i < super_classes.numel (); i++) + { + cdef_class cls = lookup_class (super_classes(i)); + + if (!error_state) + cls.delete_object (obj); + } +} + +octave_value_list +cdef_class::cdef_class_rep::meta_subsref (const std::string& type, + const std::list& idx, + int nargout) +{ + size_t skip = 1; + + octave_value_list retval; + + switch (type[0]) + { + case '(': + // Constructor call + gnulib::printf ("constructor\n"); + retval(0) = construct (idx.front ()); + break; + + case '.': + // Static method, constant (or property?) + gnulib::printf ("static method/property\n"); + if (idx.front ().length () == 1) + { + std::string nm = idx.front ()(0).string_value (); + + if (! error_state) + { + cdef_method meth = find_method (nm); + + if (meth.ok ()) + { + if (meth.is_static ()) + { + octave_value_list args; + + if (type.length () > 1 && idx.size () > 1 + && type[1] == '(') + { + args = *(++(idx.begin ())); + skip++; + } + + retval = meth.execute (args, (type.length () > skip + ? 1 : nargout), true, + "meta.class"); + } + else + ::error ("method `%s' is not static", nm.c_str ()); + } + else + { + cdef_property prop = find_property (nm); + + if (prop.ok ()) + { + if (prop.is_constant ()) + retval(0) = prop.get_value (true, "meta.class"); + else + ::error ("property `%s' is not constant", + nm.c_str ()); + } + else + ::error ("no such method or property `%s'", nm.c_str ()); + } + } + else + ::error ("invalid meta.class indexing, expected a method or property name"); + } + else + ::error ("invalid meta.class indexing"); + break; + + default: + ::error ("invalid meta.class indexing"); + break; + } + + if (! error_state) + { + if (type.length () > skip && idx.size () > skip && ! retval.empty ()) + retval = retval(0).next_subsref (nargout, type, idx, skip); + } + + return retval; +} + +void +cdef_class::cdef_class_rep::meta_release (void) +{ + cdef_manager::unregister_class (wrap ()); +} + +void +cdef_class::cdef_class_rep::initialize_object (cdef_object& obj) +{ + // Populate the object with default property values + + std::list super_classes = lookup_classes (get ("SuperClasses").cell_value ()); + + if (! error_state) + { + for (std::list::iterator it = super_classes.begin (); + ! error_state && it != super_classes.end (); ++it) + it->initialize_object (obj); + + if (! error_state) + { + for (property_const_iterator it = property_map.begin (); + ! error_state && it != property_map.end (); ++it) + { + if (! it->second.get ("Dependent").bool_value ()) + { + octave_value pvalue = it->second.get ("DefaultValue"); + + if (pvalue.is_defined ()) + obj.put (it->first, pvalue); + else + obj.put (it->first, octave_value (Matrix ())); + } + } + + if (! error_state) + { + refcount++; + obj.mark_for_construction (cdef_class (this)); + } + } + } +} + +void +cdef_class::cdef_class_rep::run_constructor (cdef_object& obj, + const octave_value_list& args) +{ + octave_value_list empty_args; + + for (std::list::const_iterator it = implicit_ctor_list.begin (); + ! error_state && it != implicit_ctor_list.end (); ++it) + { + cdef_class supcls = lookup_class (*it); + + if (! error_state) + supcls.run_constructor (obj, empty_args); + } + + if (error_state) + return; + + std::string cls_name = get_name (); + std::string ctor_name = get_base_name (cls_name); + + cdef_method ctor = find_method (ctor_name); + + if (ctor.ok ()) + { + octave_value_list ctor_args (args); + octave_value_list ctor_retval; + + ctor_args.prepend (to_ov (obj)); + ctor_retval = ctor.execute (ctor_args, 1, true, "constructor"); + + if (! error_state) + { + if (ctor_retval.length () == 1) + obj = to_cdef (ctor_retval(0)); + else + { + ::error ("%s: invalid number of output arguments for classdef constructor", + ctor_name.c_str ()); + return; + } + } + } + + obj.mark_as_constructed (wrap ()); +} + +octave_value +cdef_class::cdef_class_rep::construct (const octave_value_list& args) +{ + cdef_object obj = construct_object (args); + + if (! error_state && obj.ok ()) + return to_ov (obj); + + return octave_value (); +} + +cdef_object +cdef_class::cdef_class_rep::construct_object (const octave_value_list& args) +{ + if (! is_abstract ()) + { + cdef_object obj; + + if (is_meta_class ()) + { + // This code path is only used to create empty meta objects + // as filler for the empty values within a meta object array. + + cdef_class this_cls = wrap (); + + static cdef_object empty_class; + + if (this_cls == cdef_class::meta_class ()) + { + if (! empty_class.ok ()) + empty_class = make_class ("", std::list ()); + obj = empty_class; + } + else if (this_cls == cdef_class::meta_property ()) + { + static cdef_property empty_property; + + if (! empty_class.ok ()) + empty_class = make_class ("", std::list ()); + if (! empty_property.ok ()) + empty_property = make_property (empty_class, ""); + obj = empty_property; + } + else if (this_cls == cdef_class::meta_method ()) + { + static cdef_method empty_method; + + if (! empty_class.ok ()) + empty_class = make_class ("", std::list ()); + if (! empty_method.ok ()) + empty_method = make_method (empty_class, "", octave_value ()); + obj = empty_method; + } + else if (this_cls == cdef_class::meta_package ()) + { + static cdef_package empty_package; + + if (! empty_package.ok ()) + empty_package = make_package (""); + obj = empty_package; + } + else + panic_impossible (); + + return obj; + } + else + { + if (is_handle_class ()) + obj = cdef_object (new handle_cdef_object ()); + else + obj = cdef_object (new value_cdef_object ()); + obj.set_class (wrap ()); + + initialize_object (obj); + + if (! error_state) + { + run_constructor (obj, args); + + if (! error_state) + return obj; + } + } + } + else + error ("cannot instantiate object for abstract class `%s'", + get_name ().c_str ()); + + return cdef_object (); +} + +static octave_value +compute_attribute_value (tree_classdef_attribute* t) +{ + if (t->expression ()) + { + if (t->expression ()->is_identifier ()) + { + std::string s = t->expression ()->name (); + + if (s == "public") + return std::string ("public"); + else if (s == "protected") + return std::string ("protected"); + else if (s == "private") + return std::string ("private"); + } + + return t->expression ()->rvalue1 (); + } + else + return octave_value (true); +} + +template +static std::string +attribute_value_to_string (T* t, octave_value v) +{ + if (v.is_string ()) + return v.string_value (); + else if (t->expression ()) + return t->expression ()->original_text (); + else + return std::string ("true"); +} + +cdef_class +cdef_class::make_meta_class (tree_classdef* t) +{ + cdef_class retval; + std::string class_name, full_class_name; + + // Class creation + + class_name = full_class_name = t->ident ()->name (); + if (! t->package_name ().empty ()) + full_class_name = t->package_name () + "." + full_class_name; + gnulib::printf ("class: %s\n", full_class_name.c_str ()); + + std::list slist; + + if (t->superclass_list ()) + { + for (tree_classdef_superclass_list::iterator it = t->superclass_list ()->begin (); + ! error_state && it != t->superclass_list ()->end (); ++it) + { + std::string sclass_name = + ((*it)->package () ? (*it)->package ()->name () + "." : std::string ()) + + (*it)->ident ()->name (); + + gnulib::printf ("superclass: %s\n", sclass_name.c_str ()); + + cdef_class sclass = lookup_class (sclass_name); + + if (! error_state) + { + if (! sclass.get ("Sealed").bool_value ()) + slist.push_back (sclass); + else + { + ::error ("`%s' cannot inherit from `%s', because it is sealed", + full_class_name.c_str (), sclass_name.c_str ()); + return retval; + } + } + else + return retval; + + } + } + + retval = ::make_class (full_class_name, slist); + + if (error_state) + return cdef_class (); + + // Package owning this class + + if (! t->package_name ().empty ()) + { + cdef_package pack = cdef_manager::find_package (t->package_name ()); + + if (! error_state && pack.ok ()) + retval.put ("ContainingPackage", to_ov (pack)); + } + + // Class attributes + + if (t->attribute_list ()) + { + for (tree_classdef_attribute_list::iterator it = t->attribute_list ()->begin (); + it != t->attribute_list ()->end (); ++it) + { + std::string aname = (*it)->ident ()->name (); + octave_value avalue = compute_attribute_value (*it); + + gnulib::printf ("class attribute: %s = %s\n", aname.c_str (), + attribute_value_to_string (*it, avalue).c_str ()); + retval.put (aname, avalue); + } + } + + tree_classdef_body* b = t->body (); + + if (b) + { + // Keep track of the get/set accessor methods. They will be used + // later on when creating properties. + + std::map get_methods; + std::map set_methods; + + // Method blocks + + std::list mb_list = b->methods_list (); + + for (tree_classdef_body::methods_list_iterator it = mb_list.begin (); + it != mb_list.end (); ++it) + { + std::map amap; + gnulib::printf ("method block\n"); + + // Method attributes + + if ((*it)->attribute_list ()) + { + for (tree_classdef_attribute_list::iterator ait = (*it)->attribute_list ()->begin (); + ait != (*it)->attribute_list ()->end (); ++ait) + { + std::string aname = (*ait)->ident ()->name (); + octave_value avalue = compute_attribute_value (*ait); + + gnulib::printf ("method attribute: %s = %s\n", aname.c_str (), + attribute_value_to_string (*ait, avalue).c_str ()); + amap[aname] = avalue; + } + } + + // Methods + + if ((*it)->element_list ()) + { + for (tree_classdef_methods_list::iterator mit = (*it)->element_list ()->begin (); + mit != (*it)->element_list ()->end (); ++mit) + { + std::string mname = mit->function_value ()->name (); + std::string mprefix = mname.substr (0, 4); + + if (mprefix == "get.") + get_methods[mname.substr (4)] = + make_fcn_handle (*mit, full_class_name + ">" + mname); + else if (mprefix == "set.") + set_methods[mname.substr (4)] = + make_fcn_handle (*mit, full_class_name + ">" + mname); + else + { + cdef_method meth = make_method (retval, mname, *mit); + + gnulib::printf ("%s: %s\n", (mname == class_name ? "constructor" : "method"), + mname.c_str ()); + for (std::map::iterator ait = amap.begin (); + ait != amap.end (); ++ait) + meth.put (ait->first, ait->second); + + retval.install_method (meth); + } + } + } + } + + // Property blocks + + // FIXME: default property expression should be able to call static + // methods of the class being constructed. A restricted CLASSNAME + // symbol should be added to the scope before evaluating default + // value expressions. + + std::list pb_list = b->properties_list (); + + for (tree_classdef_body::properties_list_iterator it = pb_list.begin (); + it != pb_list.end (); ++it) + { + std::map amap; + gnulib::printf ("property block\n"); + + // Property attributes + + if ((*it)->attribute_list ()) + { + for (tree_classdef_attribute_list::iterator ait = (*it)->attribute_list ()->begin (); + ait != (*it)->attribute_list ()->end (); ++ait) + { + std::string aname = (*ait)->ident ()->name (); + octave_value avalue = compute_attribute_value (*ait); + + gnulib::printf ("property attribute: %s = %s\n", aname.c_str (), + attribute_value_to_string (*ait, avalue).c_str ()); + if (aname == "Access") + { + amap["GetAccess"] = avalue; + amap["SetAccess"] = avalue; + } + else + amap[aname] = avalue; + } + } + + // Properties + + if ((*it)->element_list ()) + { + for (tree_classdef_property_list::iterator pit = (*it)->element_list ()->begin (); + pit != (*it)->element_list ()->end (); ++pit) + { + std::string prop_name = (*pit)->ident ()->name (); + + cdef_property prop = ::make_property (retval, prop_name); + + gnulib::printf ("property: %s\n", (*pit)->ident ()->name ().c_str ()); + if ((*pit)->expression ()) + { + octave_value pvalue = (*pit)->expression ()->rvalue1 (); + + gnulib::printf ("property default: %s\n", + attribute_value_to_string (*pit, pvalue).c_str ()); + prop.put ("DefaultValue", pvalue); + } + + // Install property attributes. This is done before assigning the + // property accessors so we can do validationby using cdef_property + // methods. + + for (std::map::iterator ait = amap.begin (); + ait != amap.end (); ++ait) + prop.put (ait->first, ait->second); + + // Install property access methods, if any. Remove the accessor + // methods from the temporary storage map, so we can detect which + // ones are invalid and do not correspond to a defined property. + + std::map::iterator git = + get_methods.find (prop_name); + + if (git != get_methods.end ()) + { + prop.put ("GetMethod", git->second); + get_methods.erase (git); + } + + std::map::iterator sit = + set_methods.find (prop_name); + + if (sit != set_methods.end ()) + { + prop.put ("SetMethod", sit->second); + set_methods.erase (sit); + } + + retval.install_property (prop); + } + } + } + } + + return retval; +} + +octave_function* +cdef_class::get_method_function (const std::string& /* nm */) +{ + octave_classdef_meta* p = new octave_classdef_meta (*this); + + return p; +} + +octave_value +cdef_property::cdef_property_rep::get_value (const cdef_object& obj, + bool do_check_access, + const std::string& who) +{ + octave_value retval; + + if (do_check_access && ! check_get_access ()) + { + gripe_property_access (who, wrap (), false); + + return retval; + } + + if (! obj.is_constructed ()) + { + cdef_class cls (to_cdef (get ("DefiningClass"))); + + if (! obj.is_partially_constructed_for (cls)) + { + ::error ("cannot reference properties of class `%s' for non-constructed object", + cls.get_name ().c_str ()); + return retval; + } + } + + octave_value get_fcn = get ("GetMethod"); + + // FIXME: should check whether we're already in get accessor method + + if (get_fcn.is_empty () || is_method_executing (get_fcn, obj)) + retval = obj.get (get ("Name").string_value ()); + else + { + octave_value_list args; + + args(0) = to_ov (obj); + + args = execute_ov (get_fcn, args, 1); + + if (! error_state) + retval = args(0); + } + + return retval; +} + +octave_value +cdef_property::cdef_property_rep::get_value (bool do_check_access, + const std::string& who) +{ + if (do_check_access && ! check_get_access ()) + { + gripe_property_access (who, wrap (), false); + + return octave_value (); + } + + return get ("DefaultValue"); +} + +bool +cdef_property::cdef_property_rep::is_recursive_set (const cdef_object& /* obj */) const +{ + // FIXME: implement + return false; +} + +void +cdef_property::cdef_property_rep::set_value (cdef_object& obj, + const octave_value& val, + bool do_check_access, + const std::string& who) +{ + if (do_check_access && ! check_set_access ()) + { + gripe_property_access (who, wrap (), true); + + return; + } + + if (! obj.is_constructed ()) + { + cdef_class cls (to_cdef (get ("DefiningClass"))); + + if (! obj.is_partially_constructed_for (cls)) + { + ::error ("cannot reference properties of class `%s' for non-constructed object", + cls.get_name ().c_str ()); + return; + } + } + + octave_value set_fcn = get ("SetMethod"); + + if (set_fcn.is_empty () || is_method_executing (set_fcn, obj)) + obj.put (get ("Name").string_value (), val); + else + { + octave_value_list args; + + args(0) = to_ov (obj); + args(1) = val; + + args = execute_ov (set_fcn, args, 1); + + if (! error_state) + { + if (args.length() > 0) + { + cdef_object new_obj = to_cdef (args(0)); + + if (! error_state) + obj = new_obj; + } + } + } +} + +bool +cdef_property::cdef_property_rep::check_get_access (void) const +{ + cdef_class cls (to_cdef (get ("DefiningClass"))); + + if (! error_state) + return ::check_access (cls, get ("GetAccess")); + + return false; +} + +bool +cdef_property::cdef_property_rep::check_set_access (void) const +{ + cdef_class cls (to_cdef (get ("DefiningClass"))); + + if (! error_state) + return ::check_access (cls, get ("SetAccess")); + + return false; +} + +void +cdef_method::cdef_method_rep::check_method (void) +{ + // FIXME: check whether re-load is needed +} + +octave_value_list +cdef_method::cdef_method_rep::execute (const octave_value_list& args, + int nargout, bool do_check_access, + const std::string& who) +{ + octave_value_list retval; + + if (do_check_access && ! check_access ()) + { + gripe_method_access (who, wrap ()); + + return retval; + } + + if (! get ("Abstract").bool_value ()) + { + check_method (); + + if (function.is_defined ()) + { + retval = execute_ov (function, args, nargout); + } + } + else + error ("%s: cannot execute abstract method", + get ("Name").string_value ().c_str ()); + + return retval; +} + +octave_value_list +cdef_method::cdef_method_rep::execute (const cdef_object& obj, + const octave_value_list& args, + int nargout, bool do_check_access, + const std::string& who) +{ + octave_value_list retval; + + if (do_check_access && ! check_access ()) + { + gripe_method_access (who, wrap ()); + + return retval; + } + + if (! get ("Abstract").bool_value ()) + { + check_method (); + + octave_value_list new_args; + + if (function.is_defined ()) + { + new_args.resize (args.length () + 1); + + new_args(0) = to_ov (obj); + for (int i = 0; i < args.length (); i++) + new_args(i+1) = args(i); + + retval = execute_ov (function, new_args, nargout); + } + } + else + error ("%s: cannot execute abstract method", + get ("Name").string_value ().c_str ()); + + return retval; +} + +bool +cdef_method::cdef_method_rep::is_constructor (void) const +{ + if (function.is_function()) + return function.function_value ()->is_classdef_constructor (); + + return false; +} + +bool +cdef_method::cdef_method_rep::check_access (void) const +{ + cdef_class cls (to_cdef (get ("DefiningClass"))); + + if (! error_state) + return ::check_access (cls, get ("Access")); + + return false; +} + +octave_value_list +cdef_method::cdef_method_rep::meta_subsref + (const std::string& type, const std::list& idx, + int nargout) +{ + octave_value_list retval; + + switch (type[0]) + { + case '(': + retval = execute (idx.front (), type.length () > 1 ? 1 : nargout, true); + break; + + default: + error ("invalid meta.method indexing"); + break; + } + + if (! error_state) + { + if (type.length () > 1 && idx.size () > 1 && ! retval.empty ()) + retval = retval(0).next_subsref (nargout, type, idx, 1); + } + + return retval; +} + +static cdef_package +lookup_package (const std::string& name) +{ + return cdef_manager::find_package (name); +} + +static octave_value_list +package_fromName (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval; + + if (args.length () == 1) + { + std::string name = args(0).string_value (); + + if (! error_state) + retval(0) = to_ov (lookup_package (name)); + else + error ("fromName: invalid package name, expected a string value"); + } + else + error ("fromName: invalid number of parameters"); + + return retval; +} + +static octave_value_list +package_get_classes (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval (1, Matrix ()); + + if (args.length () == 1 && args(0).type_name () == "object" + && args(0).class_name () == "meta.package") + { + cdef_package pack (to_cdef (args(0))); + + retval(0) = pack.get_classes (); + } + + return retval; +} + +static octave_value_list +package_get_functions (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval (1, Matrix ()); + + if (args.length () == 0 && args(0).type_name () == "object" + && args(0).class_name () == "meta.package") + { + cdef_package pack (to_cdef (args(0))); + + retval(0) = pack.get_functions (); + } + + return retval; +} + +static octave_value_list +package_get_packages (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval (1, Matrix ()); + + if (args.length () == 0 && args(0).type_name () == "object" + && args(0).class_name () == "meta.package") + { + cdef_package pack (to_cdef (args(0))); + + retval(0) = pack.get_packages (); + } + + return retval; +} + +static octave_value_list +package_getAllPackages (const octave_value_list& /* args */, + int /* nargout */) +{ + std::map toplevel_packages; + + std::list names = load_path::get_all_package_names (); + + toplevel_packages["meta"] = cdef_manager::find_package ("meta", false, + false); + + for (std::list::const_iterator it = names.begin (); + it != names.end (); ++it) + toplevel_packages[*it] = cdef_manager::find_package (*it, false, true); + + Cell c (toplevel_packages.size (), 1); + + int i = 0; + + for (std::map::const_iterator it = toplevel_packages.begin (); + it != toplevel_packages.end (); ++it) + c(i++,0) = to_ov (it->second); + + return octave_value_list (octave_value (c)); +} + +void +cdef_package::cdef_package_rep::install_class (const cdef_class& cls, + const std::string& nm) +{ + class_map[nm] = cls; + + member_count++; +} + +void +cdef_package::cdef_package_rep::install_function (const octave_value& fcn, + const std::string& nm) +{ + function_map[nm] = fcn; +} + +void +cdef_package::cdef_package_rep::install_package (const cdef_package& pack, + const std::string& nm) +{ + package_map[nm] = pack; + + member_count++; +} + +template +Cell +map2Cell (const std::map& m) +{ + Cell retval (1, m.size ()); + int i = 0; + + for (typename std::map::const_iterator it = m.begin (); + it != m.end (); ++it, ++i) + { + retval(i) = to_ov (it->second); + } + + return retval; +} + +Cell +cdef_package::cdef_package_rep::get_classes (void) const +{ return map2Cell (class_map); } + +Cell +cdef_package::cdef_package_rep::get_functions (void) const +{ return map2Cell (function_map); } + +Cell +cdef_package::cdef_package_rep::get_packages (void) const +{ return map2Cell (package_map); } + +octave_value +cdef_package::cdef_package_rep::find (const std::string& nm) +{ + std::string symbol_name = get_name () + "." + nm; + + return symbol_table::find (symbol_name, octave_value_list (), true, false); +} + +octave_value_list +cdef_package::cdef_package_rep::meta_subsref + (const std::string& type, const std::list& idx, + int nargout) +{ + octave_value_list retval; + + switch (type[0]) + { + case '.': + if (idx.front ().length () == 1) + { + std::string nm = idx.front ()(0).string_value (); + + if (! error_state) + { + gnulib::printf ("meta.package query: %s\n", nm.c_str ()); + + octave_value o = find (nm); + + if (o.is_defined ()) + { + if (o.is_function ()) + { + octave_function* fcn = o.function_value (); + + if (! error_state) + { + if (type.size () == 1 || + ! fcn->is_postfix_index_handled (type[1])) + { + octave_value_list tmp_args; + + retval = o.do_multi_index_op (nargout, + tmp_args); + } + else + retval(0) = o; + + if (type.size () > 1 && idx.size () > 1) + retval = retval(0).next_subsref (nargout, type, + idx, 1); + } + } + else if (type.size () > 1 && idx.size () > 1) + retval = o.next_subsref (nargout, type, idx, 1); + else + retval(0) = o; + } + else + error ("member `%s' in package `%s' does not exist", + nm.c_str (), get_name ().c_str ()); + } + else + error ("invalid meta.package indexing, expected a symbol name"); + } + else + error ("invalid meta.package indexing"); + break; + + default: + error ("invalid meta.package indexing"); + break; + } + + return retval; +} + +void +cdef_package::cdef_package_rep::meta_release (void) +{ + // FIXME: Do we really want to unregister the package, as it + // could still be referenced by classes or sub-packages? + // If the package object is recreated later on, it won't + // match the one already referenced by those classes or + // sub-packages. + + //cdef_manager::unregister_package (wrap ()); +} + +cdef_class cdef_class::_meta_class = cdef_class (); +cdef_class cdef_class::_meta_property = cdef_class (); +cdef_class cdef_class::_meta_method = cdef_class (); +cdef_class cdef_class::_meta_package = cdef_class (); + +cdef_package cdef_package::_meta = cdef_package (); + +void +install_classdef (void) +{ + octave_classdef::register_type (); + + /* bootstrap */ + cdef_class handle = make_class ("handle"); + cdef_class meta_class = cdef_class::_meta_class = make_meta_class ("meta.class", handle); + handle.set_class (meta_class); + meta_class.set_class (meta_class); + + /* meta classes */ + cdef_class meta_property = cdef_class::_meta_property = make_meta_class ("meta.property", handle); + cdef_class meta_method = cdef_class::_meta_method = make_meta_class ("meta.method", handle); + cdef_class meta_package = cdef_class::_meta_package = make_meta_class ("meta.package", handle); + + cdef_class meta_event = make_meta_class ("meta.event", handle); + cdef_class meta_dynproperty = make_meta_class ("meta.dynamicproperty", handle); + + /* meta.class properties */ + meta_class.install_property (make_attribute (meta_class, "Abstract")); + meta_class.install_property (make_attribute (meta_class, "ConstructOnLoad")); + meta_class.install_property (make_property (meta_class, "ContainingPackage")); + meta_class.install_property (make_property (meta_class, "Description")); + meta_class.install_property (make_property (meta_class, "DetailedDescription")); + meta_class.install_property (make_property (meta_class, "Events")); + meta_class.install_property (make_attribute (meta_class, "HandleCompatible")); + meta_class.install_property (make_attribute (meta_class, "Hidden")); + meta_class.install_property + (make_property (meta_class, "InferiorClasses", + make_fcn_handle (class_get_inferiorclasses, "meta.class>get.InferiorClasses"), + "public", Matrix (), "private")); + meta_class.install_property + (make_property (meta_class, "Methods", + make_fcn_handle (class_get_methods, "meta.class>get.Methods"), + "public", Matrix (), "private")); + meta_class.install_property + (make_property (meta_class, "MethodList", + make_fcn_handle (class_get_methods, "meta.class>get.MethodList"), + "public", Matrix (), "private")); + meta_class.install_property (make_attribute (meta_class, "Name")); + meta_class.install_property + (make_property (meta_class, "Properties", + make_fcn_handle (class_get_properties, "meta.class>get.Properties"), + "public", Matrix (), "private")); + meta_class.install_property + (make_property (meta_class, "PropertyList", + make_fcn_handle (class_get_properties, "meta.class>get.PropertyList"), + "public", Matrix (), "private")); + meta_class.install_property (make_attribute (meta_class, "Sealed")); + meta_class.install_property + (make_property (meta_class, "SuperClasses", + make_fcn_handle (class_get_superclasses, "meta.class>get.SuperClasses"), + "public", Matrix (), "private")); + meta_class.install_property + (make_property (meta_class, "SuperClassList", + make_fcn_handle (class_get_superclasses, "meta.class>get.SuperClassList"), + "public", Matrix (), "private")); + /* meta.class methods */ + meta_class.install_method (make_method (meta_class, "fromName", class_fromName, + "public", true)); + meta_class.install_method (make_method (meta_class, "fevalStatic", class_fevalStatic, + "public", false)); + meta_class.install_method (make_method (meta_class, "getConstant", class_getConstant, + "public", false)); + meta_class.install_method (make_method (meta_class, "eq", class_eq)); + meta_class.install_method (make_method (meta_class, "ne", class_ne)); + meta_class.install_method (make_method (meta_class, "lt", class_lt)); + meta_class.install_method (make_method (meta_class, "le", class_le)); + meta_class.install_method (make_method (meta_class, "gt", class_gt)); + meta_class.install_method (make_method (meta_class, "ge", class_ge)); + + /* meta.method properties */ + meta_method.install_property (make_attribute (meta_method, "Abstract")); + meta_method.install_property (make_attribute (meta_method, "Access")); + meta_method.install_property (make_attribute (meta_method, "DefiningClass")); + meta_method.install_property (make_attribute (meta_method, "Description")); + meta_method.install_property (make_attribute (meta_method, "DetailedDescription")); + meta_method.install_property (make_attribute (meta_method, "Hidden")); + meta_method.install_property (make_attribute (meta_method, "Name")); + meta_method.install_property (make_attribute (meta_method, "Sealed")); + meta_method.install_property (make_attribute (meta_method, "Static")); + + /* meta.property properties */ + meta_property.install_property (make_attribute (meta_property, "Name")); + meta_property.install_property (make_attribute (meta_property, "Description")); + meta_property.install_property (make_attribute (meta_property, "DetailedDescription")); + meta_property.install_property (make_attribute (meta_property, "Abstract")); + meta_property.install_property (make_attribute (meta_property, "Constant")); + meta_property.install_property (make_attribute (meta_property, "GetAccess")); + meta_property.install_property (make_attribute (meta_property, "SetAccess")); + meta_property.install_property (make_attribute (meta_property, "Dependent")); + meta_property.install_property (make_attribute (meta_property, "Transient")); + meta_property.install_property (make_attribute (meta_property, "Hidden")); + meta_property.install_property (make_attribute (meta_property, "GetObservable")); + meta_property.install_property (make_attribute (meta_property, "SetObservable")); + meta_property.install_property (make_attribute (meta_property, "GetMethod")); + meta_property.install_property (make_attribute (meta_property, "SetMethod")); + meta_property.install_property (make_attribute (meta_property, "DefiningClass")); + meta_property.install_property + (make_property (meta_property, "DefaultValue", + make_fcn_handle (property_get_defaultvalue, "meta.property>get.DefaultValue"), + "public", Matrix (), "private")); + meta_property.install_property (make_attribute (meta_property, "HasDefault")); + /* meta.property events */ + // FIXME: add events + + /* handle methods */ + handle.install_method (make_method (handle, "delete", handle_delete)); + + /* meta.package properties */ + meta_package.install_property (make_attribute (meta_package, "Name")); + meta_package.install_property (make_property (meta_package, "ContainingPackage")); + meta_package.install_property + (make_property (meta_package, "ClassList", + make_fcn_handle (package_get_classes, "meta.package>get.ClassList"), + "public", Matrix (), "private")); + meta_package.install_property + (make_property (meta_package, "Classes", + make_fcn_handle (package_get_classes, "meta.package>get.Classes"), + "public", Matrix (), "private")); + meta_package.install_property + (make_property (meta_package, "FunctionList", + make_fcn_handle (package_get_functions, "meta.package>get.FunctionList"), + "public", Matrix (), "private")); + meta_package.install_property + (make_property (meta_package, "Functions", + make_fcn_handle (package_get_functions, "meta.package>get.Functions"), + "public", Matrix (), "private")); + meta_package.install_property + (make_property (meta_package, "PackageList", + make_fcn_handle (package_get_packages, "meta.package>get.PackageList"), + "public", Matrix (), "private")); + meta_package.install_property + (make_property (meta_package, "Packages", + make_fcn_handle (package_get_packages, "meta.package>get.Packages"), + "public", Matrix (), "private")); + meta_package.install_method (make_method (meta_package, "fromName", package_fromName, + "public", true)); + meta_package.install_method (make_method (meta_package, "getAllPackages", package_getAllPackages, + "public", true)); + + /* create "meta" package */ + cdef_package package_meta = cdef_package::_meta = make_package ("meta"); + package_meta.install_class (meta_class, "class"); + package_meta.install_class (meta_property, "property"); + package_meta.install_class (meta_method, "method"); + package_meta.install_class (meta_package, "package"); + package_meta.install_class (meta_event, "event"); + package_meta.install_class (meta_dynproperty, "dynproperty"); + + /* install built-in classes into the symbol table */ + symbol_table::install_built_in_function + ("meta.class", octave_value (meta_class.get_constructor_function ())); + symbol_table::install_built_in_function + ("meta.method", octave_value (meta_method.get_constructor_function ())); + symbol_table::install_built_in_function + ("meta.property", octave_value (meta_property.get_constructor_function ())); + symbol_table::install_built_in_function + ("meta.package", octave_value (meta_package.get_constructor_function ())); + symbol_table::install_built_in_function + ("meta.event", octave_value (meta_event.get_constructor_function ())); + symbol_table::install_built_in_function + ("meta.dynproperty", octave_value (meta_dynproperty.get_constructor_function ())); +} + +//---------------------------------------------------------------------------- + +cdef_manager* cdef_manager::instance = 0; + +void +cdef_manager::create_instance (void) +{ + instance = new cdef_manager (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); +} + +cdef_class +cdef_manager::do_find_class (const std::string& name, + bool error_if_not_found, bool load_if_not_found) +{ + std::map::iterator it = all_classes.find (name); + + if (it == all_classes.end ()) + { + if (load_if_not_found) + { + octave_value ov_cls; + + size_t pos = name.rfind ('.'); + + if (pos == std::string::npos) + ov_cls = symbol_table::find (name); + else + { + std::string pack_name = name.substr (0, pos); + + cdef_package pack = do_find_package (pack_name, false, true); + + if (pack.ok ()) + ov_cls = pack.find (name.substr (pos+1)); + } + + if (ov_cls.is_defined ()) + it = all_classes.find (name); + } + } + + if (it == all_classes.end ()) + { + if (error_if_not_found) + error ("class not found: %s", name.c_str ()); + } + else + { + cdef_class cls = it->second; + + if (! cls.is_builtin ()) + cls = lookup_class (cls); + + if (cls.ok ()) + return cls; + else + all_classes.erase (it); + } + + return cdef_class (); +} + +octave_function* +cdef_manager::do_find_method_symbol (const std::string& method_name, + const std::string& class_name) +{ + octave_function *retval = 0; + + cdef_class cls = find_class (class_name, false, false); + + if (cls.ok ()) + { + cdef_method meth = cls.find_method (method_name); + + if (meth.ok ()) + retval = new octave_classdef_meta (meth); + } + + return retval; +} + +cdef_package +cdef_manager::do_find_package (const std::string& name, + bool error_if_not_found, + bool load_if_not_found) +{ + cdef_package retval; + + std::map::const_iterator it + = all_packages.find (name); + + if (it != all_packages.end ()) + { + retval = it->second; + + if (! retval.ok ()) + error ("invalid package `%s'", name.c_str ()); + } + else + { + if (load_if_not_found && load_path::find_package (name)) + { + size_t pos = name.find ('.'); + + if (pos == std::string::npos) + retval = make_package (name, std::string ()); + else + { + std::string parent_name = name.substr (0, pos); + + retval = make_package (name, parent_name); + } + } + else if (error_if_not_found) + error ("unknown package `%s'", name.c_str ()); + } + + return retval; +} + +octave_function* +cdef_manager::do_find_package_symbol (const std::string& pack_name) +{ + octave_function* retval = 0; + + cdef_package pack = find_package (pack_name, false); + + if (pack.ok ()) + retval = new octave_classdef_meta (pack); + + return retval; +} + +//---------------------------------------------------------------------------- + +DEFUN (__meta_get_package__, args, , "") +{ + octave_value retval; + + if (args.length () == 1) + { + std::string cname = args(0).string_value (); + + if (! error_state) + retval = to_ov (lookup_package (cname)); + else + error ("invalid package name, expected a string value"); + } + else + print_usage (); + + return retval; +} + +DEFUN (__superclass_reference__, args, /* nargout */, + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} __superclass_reference__ ()\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + return octave_value (new octave_classdef_superclass_ref (args)); +} + +DEFUN (__meta_class_query__, args, /* nargout */, + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} __meta_class_query__ ()\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + octave_value retval; + + std::cerr << "__meta_class_query__ (" + << args(0).string_value () << ", " + << args(1).string_value () << ")" + << std::endl; + + if (args.length () == 2) + { + std::string pkg = args(0).string_value (); + std::string cls = args(1).string_value (); + + if (! pkg.empty ()) + cls = pkg + "." + cls; + + if (! error_state) + retval = to_ov (lookup_class (cls)); + else + error ("invalid class name, expected a string value"); + } + else + print_usage (); + + return retval; +} + +DEFUN (metaclass, args, /* nargout */, + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} metaclass (obj)\n\ +Returns the meta.class object corresponding to the class of @var{obj}.\n\ +@end deftypefn") +{ + octave_value retval; + + if (args.length () == 1) + { + cdef_object obj = to_cdef (args(0)); + + if (! error_state) + retval = to_ov (obj.get_class ()); + else + print_usage (); + } + else + print_usage (); + + return retval; +} + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; End: *** +*/ diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/octave-value/ov-classdef.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/octave-value/ov-classdef.h Thu Dec 05 12:04:40 2013 -0500 @@ -0,0 +1,1653 @@ +/* + +Copyright (C) 2012-2013 Michael Goffioul + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_classdef_h) +#define octave_classdef_h 1 + +#include +#include +#include + +#include "oct-map.h" +#include "oct-refcount.h" +#include "ov-base.h" +#include "symtab.h" + +class cdef_object; +class cdef_class; +class cdef_property; +class cdef_method; +class cdef_package; + +class tree_classdef; + +// This is mainly a boostrap class to declare the expected interface. +// The actual base class is cdef_class_base, which is declared after +// cdef_object, such that it can contain cdef_object objects. +class +cdef_object_rep +{ +public: + friend class cdef_object; + +public: + cdef_object_rep (void) : refcount (1) { } + + virtual ~cdef_object_rep (void) { } + + virtual cdef_class get_class (void) const; + + virtual void set_class (const cdef_class&) + { gripe_invalid_object ("set_class"); } + + virtual cdef_object_rep* clone (void) const + { + gripe_invalid_object ("clone"); + return new cdef_object_rep (); + } + + virtual cdef_object_rep* empty_clone (void) const + { + gripe_invalid_object ("empty_clone"); + return new cdef_object_rep (); + } + + virtual cdef_object_rep* copy (void) const + { + gripe_invalid_object ("copy"); + return new cdef_object_rep (); + } + + virtual cdef_object_rep* make_array (void) const + { + gripe_invalid_object ("make_array"); + return new cdef_object_rep (); + } + + virtual bool is_array (void) const { return false; } + + virtual bool is_value_object (void) const { return false; } + + virtual bool is_handle_object (void) const { return false; } + + virtual bool is_meta_object (void) const { return false; } + + virtual Array array_value (void) const + { + gripe_invalid_object ("array_value"); + return Array (); + } + + virtual void put (const std::string&, const octave_value&) + { gripe_invalid_object ("put"); } + + virtual octave_value get (const std::string&) const + { + gripe_invalid_object ("get"); + return octave_value (); + } + + virtual octave_value_list + subsref (const std::string&, const std::list&, + int, size_t&, const cdef_class&, bool) + { + gripe_invalid_object ("subsref"); + return octave_value_list (); + } + + virtual octave_value + subsasgn (const std::string&, const std::list&, + const octave_value&) + { + gripe_invalid_object ("subsasgn"); + return octave_value (); + } + + virtual string_vector map_keys(void) const; + + virtual bool is_valid (void) const { return false; } + + std::string class_name (void) const; + + virtual void mark_for_construction (const cdef_class&) + { gripe_invalid_object ("mark_for_construction"); } + + virtual bool is_constructed_for (const cdef_class&) const + { + gripe_invalid_object ("is_constructed_for"); + return false; + } + + virtual bool is_partially_constructed_for (const cdef_class&) const + { + gripe_invalid_object ("is_partially_constructed_for"); + return false; + } + + virtual void mark_as_constructed (void) + { gripe_invalid_object ("mark_as_constructed"); } + + virtual void mark_as_constructed (const cdef_class&) + { gripe_invalid_object ("mark_as_constructed"); } + + virtual bool is_constructed (void) const + { + gripe_invalid_object ("is_constructed"); + return false; + } + + virtual octave_idx_type static_count (void) const { return 0; } + + virtual void destroy (void) { delete this; } + + void release (void) + { + if (--refcount == static_count ()) + destroy (); + } + + virtual dim_vector dims (void) const { return dim_vector (); } + +protected: + /* reference count */ + octave_refcount refcount; + +protected: + /* Restricted copying */ + cdef_object_rep (const cdef_object_rep&) + : refcount (1) { } + +private: + /* No assignment */ + cdef_object_rep& operator = (const cdef_object_rep& ); + + void gripe_invalid_object (const char *who) const + { error ("%s: invalid object", who); } +}; + +class +cdef_object +{ +public: + /* FIXME: use a null object */ + cdef_object (void) + : rep (new cdef_object_rep ()) { } + + cdef_object (const cdef_object& obj) + : rep (obj.rep) + { + rep->refcount++; + } + + cdef_object (cdef_object_rep *r) + : rep (r) { } + + virtual ~cdef_object (void) + { rep->release (); } + + cdef_object& operator = (const cdef_object& obj) + { + if (rep != obj.rep) + { + rep->release (); + + rep = obj.rep; + rep->refcount++; + } + + return *this; + } + + cdef_class get_class (void) const; + + void set_class (const cdef_class& cls) { rep->set_class (cls); } + + std::string class_name (void) const + { return rep->class_name (); } + + cdef_object clone (void) const + { return cdef_object (rep->clone ()); } + + cdef_object empty_clone (void) const + { return cdef_object (rep->empty_clone ()); } + + dim_vector dims (void) const { return rep->dims (); } + + cdef_object make_array (void) const + { return cdef_object (rep->make_array ()); } + + cdef_object copy (void) const + { return cdef_object (rep->copy ()); } + + bool is_array (void) const { return rep->is_array (); } + + bool is_value_object (void) const { return rep->is_value_object (); } + + bool is_handle_object (void) const { return rep->is_handle_object (); } + + bool is_meta_object (void) const { return rep->is_meta_object (); } + + Array array_value (void) const { return rep->array_value (); } + + void put (const std::string& pname, const octave_value& val) + { rep->put (pname, val); } + + octave_value get (const std::string& pname) const + { return rep->get (pname); } + + octave_value_list + subsref (const std::string& type, const std::list& idx, + int nargout, size_t& skip, const cdef_class& context, + bool auto_add = false) + { return rep->subsref (type, idx, nargout, skip, context, auto_add); } + + octave_value + subsasgn (const std::string& type, const std::list& idx, + const octave_value& rhs, int ignore_copies = 0) + { + make_unique (ignore_copies); + return rep->subsasgn (type, idx, rhs); + } + + string_vector map_keys (void) const { return rep->map_keys (); } + + const cdef_object_rep* get_rep (void) const { return rep; } + + bool ok (void) const { return rep->is_valid (); } + + void mark_for_construction (const cdef_class& cls) + { rep->mark_for_construction (cls); } + + bool is_constructed (void) const { return rep->is_constructed (); } + + bool is_constructed_for (const cdef_class& cls) const + { return rep->is_constructed_for (cls); } + + bool is_partially_constructed_for (const cdef_class& cls) const + { return rep->is_partially_constructed_for (cls); } + + void mark_as_constructed (void) { rep->mark_as_constructed (); } + + void mark_as_constructed (const cdef_class& cls) + { rep->mark_as_constructed (cls); } + + bool is (const cdef_object& obj) const { return rep == obj.rep; } + +protected: + cdef_object_rep* get_rep (void) { return rep; } + + void make_unique (int ignore_copies) + { + if (rep->refcount > ignore_copies + 1) + *this = clone (); + } + +private: + cdef_object_rep *rep; +}; + +class +cdef_object_base : public cdef_object_rep +{ +public: + cdef_object_base (void) + : cdef_object_rep (), klass () + { + register_object (); + } + + ~cdef_object_base (void) { unregister_object (); } + + cdef_class get_class (void) const; + + void set_class (const cdef_class& cls); + + cdef_object_rep* empty_clone (void) const + { return new cdef_object_base (*this); } + + cdef_object_rep* make_array (void) const; + +protected: + // Restricted copying! + cdef_object_base (const cdef_object_base& obj) + : cdef_object_rep (obj), klass (obj.klass) + { + register_object (); + } + +private: + void register_object (void); + + void unregister_object (void); + +private: + // The class of the object + cdef_object klass; + +private: + // No assignment! + cdef_object_base& operator = (const cdef_object_base&); +}; + +class +cdef_object_array : public cdef_object_base +{ +public: + cdef_object_array (void) : cdef_object_base () { } + + cdef_object_array (const Array& a) + : cdef_object_base (), array (a) { } + + cdef_object_rep* clone (void) const + { return new cdef_object_array (*this); } + + dim_vector dims (void) const { return array.dims (); } + + bool is_valid (void) const { return true; } + + bool is_array (void) const { return true; } + + Array array_value (void) const { return array; } + + octave_value_list + subsref (const std::string& type, const std::list& idx, + int nargout, size_t& skip, const cdef_class& context, + bool auto_add); + + octave_value + subsasgn (const std::string& type, const std::list& idx, + const octave_value& rhs); + +private: + Array array; + +private: + void fill_empty_values (void) { fill_empty_values (array); } + + void fill_empty_values (Array& arr); + + // Private copying! + cdef_object_array (const cdef_object_array& obj) + : cdef_object_base (obj), array (obj.array) { } + + // No assignment! + cdef_object_array& operator = (const cdef_object_array&); +}; + +class +cdef_object_scalar : public cdef_object_base +{ +public: + cdef_object_scalar (void) : cdef_object_base () { } + + ~cdef_object_scalar (void) { } + + dim_vector dims (void) const { return dim_vector (1, 1); } + + void put (const std::string& pname, const octave_value& val) + { map.assign (pname, val); } + + octave_value get (const std::string& pname) const + { + Cell val = map.contents (pname); + + if (val.numel () > 0) + return val(0, 0); + else + { + error ("get: unknown slot: %s", pname.c_str ()); + return octave_value (); + } + } + + octave_value_list + subsref (const std::string& type, const std::list& idx, + int nargout, size_t& skip, const cdef_class& context, + bool auto_add); + + octave_value + subsasgn (const std::string& type, const std::list& idx, + const octave_value& rhs); + + void mark_for_construction (const cdef_class&); + + bool is_constructed_for (const cdef_class& cls) const; + + bool is_partially_constructed_for (const cdef_class& cls) const; + + void mark_as_constructed (void) { ctor_list.clear (); } + + void mark_as_constructed (const cdef_class& cls) { ctor_list.erase (cls); } + + bool is_constructed (void) const { return ctor_list.empty (); } + +protected: + // Object property values + Octave_map map; + + // Internal/temporary structure used during object construction + std::map< cdef_class, std::list > ctor_list; + +protected: + // Restricted object copying! + cdef_object_scalar (const cdef_object_scalar& obj) + : cdef_object_base (obj), map (obj.map), ctor_list (obj.ctor_list) { } + +private: + // No assignment! + cdef_object_scalar& operator = (const cdef_object_scalar&); +}; + +class +handle_cdef_object : public cdef_object_scalar +{ +public: + handle_cdef_object (void) + : cdef_object_scalar () { } + + ~handle_cdef_object (void); + + cdef_object_rep* clone (void) const + { + handle_cdef_object *obj = const_cast (this); + obj->refcount++; + return obj; + } + + cdef_object_rep* copy (void) const + { return new handle_cdef_object (*this); } + + bool is_valid (void) const { return true; } + + bool is_handle_object (void) const { return true; } + +protected: + // Restricted copying! + handle_cdef_object (const handle_cdef_object& obj) + : cdef_object_scalar (obj) { } + +private: + // No assignment + handle_cdef_object& operator = (const handle_cdef_object&); +}; + +class +value_cdef_object : public cdef_object_scalar +{ +public: + value_cdef_object (void) + : cdef_object_scalar () { } + + ~value_cdef_object (void); + + cdef_object_rep* clone (void) const + { return new value_cdef_object (*this); } + + cdef_object_rep* copy (void) const { return clone (); } + + bool is_valid (void) const { return true; } + + bool is_value_object (void) const { return true; } + +private: + // Private copying! + value_cdef_object (const value_cdef_object& obj) + : cdef_object_scalar (obj) { } + + // No assignment! + value_cdef_object& operator = (const value_cdef_object&); +}; + +class +cdef_meta_object_rep : public handle_cdef_object +{ +public: + cdef_meta_object_rep (void) + : handle_cdef_object () { } + + ~cdef_meta_object_rep (void) { } + + cdef_object_rep* copy (void) const + { return new cdef_meta_object_rep (*this); } + + bool is_meta_object (void) const { return true; } + + virtual bool is_class (void) const { return false; } + + virtual bool is_property (void) const { return false; } + + virtual bool is_method (void) const { return false; } + + virtual bool is_package (void) const { return false; } + + virtual octave_value_list + meta_subsref (const std::string& /* type */, + const std::list& /* idx */, + int /* nargout */) + { + ::error ("subsref: invalid meta object"); + return octave_value_list (); + } + + virtual void meta_release (void) { } + + virtual bool meta_is_postfix_index_handled (char /* type */) const + { return false; } + +protected: + // Restricted copying! + cdef_meta_object_rep (const cdef_meta_object_rep& obj) + : handle_cdef_object (obj) { } + +private: + // No assignment! + cdef_meta_object_rep& operator = (const cdef_meta_object_rep&); +}; + +class +cdef_meta_object : public cdef_object +{ +public: + cdef_meta_object (void) + : cdef_object () { } + + cdef_meta_object (const cdef_meta_object& obj) + : cdef_object (obj) { } + + cdef_meta_object (cdef_meta_object_rep *r) + : cdef_object (r) { } + + // Object consistency is checked in sub-classes. + cdef_meta_object (const cdef_object& obj) + : cdef_object (obj) { } + + ~cdef_meta_object (void) { } + + bool is_class (void) const { return get_rep ()->is_class (); } + + bool is_property (void) const { return get_rep ()->is_property (); } + + bool is_method (void) const { return get_rep ()->is_method (); } + + bool is_package (void) const { return get_rep ()->is_package (); } + + octave_value_list + meta_subsref (const std::string& type, + const std::list& idx, int nargout) + { return get_rep ()->meta_subsref (type, idx, nargout); } + + void meta_release (void) { get_rep ()->meta_release (); } + + bool meta_is_postfix_index_handled (char type) const + { return get_rep ()->meta_is_postfix_index_handled (type); } + +private: + cdef_meta_object_rep* get_rep (void) + { return dynamic_cast (cdef_object::get_rep ()); } + + const cdef_meta_object_rep* get_rep (void) const + { return dynamic_cast (cdef_object::get_rep ()); } +}; + +class +cdef_class : public cdef_meta_object +{ +private: + + class + cdef_class_rep : public cdef_meta_object_rep + { + public: + cdef_class_rep (void) + : cdef_meta_object_rep (), member_count (0), handle_class (false), + object_count (0), meta (false) { } + + cdef_class_rep (const std::list& superclasses); + + cdef_object_rep* copy (void) const { return new cdef_class_rep (*this); } + + bool is_class (void) const { return true; } + + std::string get_name (void) const + { return get ("Name").string_value (); } + + void set_name (const std::string& nm) { put ("Name", nm); } + + bool is_abstract (void) const { return get ("Abstract").bool_value (); } + + bool is_sealed (void) const { return get ("Sealed").bool_value (); } + + cdef_method find_method (const std::string& nm, bool local = false); + + void install_method (const cdef_method& meth); + + Cell get_methods (void); + + cdef_property find_property (const std::string& nm); + + void install_property (const cdef_property& prop); + + Cell get_properties (void); + + string_vector get_names (void); + + void set_directory (const std::string& dir) { directory = dir; } + + std::string get_directory (void) const { return directory; } + + void delete_object (cdef_object obj); + + octave_value_list + meta_subsref (const std::string& type, + const std::list& idx, int nargout); + + void meta_release (void); + + bool meta_is_postfix_index_handled (char type) const + { return (type == '(' || type == '.'); } + + octave_value construct (const octave_value_list& args); + + cdef_object construct_object (const octave_value_list& args); + + void initialize_object (cdef_object& obj); + + void run_constructor (cdef_object& obj, const octave_value_list& args); + + void mark_as_handle_class (void) { handle_class = true; } + + bool is_handle_class (void) const { return handle_class; } + + void register_object (void) { object_count++; } + + void unregister_object (void) { object_count--; } + + octave_idx_type static_count (void) const { return member_count; } + + void destroy (void) + { + if (member_count) + { + refcount++; + cdef_class lock (this); + + member_count = 0; + method_map.clear (); + property_map.clear (); + } + else + delete this; + } + + void mark_as_meta_class (void) { meta = true; } + + bool is_meta_class (void) const { return meta; } + + private: + void load_all_methods (void); + + void find_names (std::set& names, bool all); + + void find_properties (std::map& props, + bool only_inherited); + + void find_methods (std::map& meths, + bool only_inherited); + + cdef_class wrap (void) + { + refcount++; + return cdef_class (this); + } + + private: + // The @-directory were this class is loaded from. + // (not used yet) + std::string directory; + + // The methods defined by this class. + std::map method_map; + + // The properties defined by this class. + std::map property_map; + + // The number of members in this class (methods, properties...) + octave_idx_type member_count; + + // TRUE if this class is a handle class. A class is a handle + // class when the abstract "handle" class is one of its superclasses. + bool handle_class; + + // The list of super-class constructors that are called implicitly by the + // the classdef engine when creating an object. These constructors are not + // called explicitly by the class constructor. + std::list implicit_ctor_list; + + // The number of objects of this class. + octave_refcount object_count; + + // TRUE if this class is a built-in meta class. + bool meta; + + // Utility iterator typedef's. + typedef std::map::iterator method_iterator; + typedef std::map::const_iterator method_const_iterator; + typedef std::map::iterator property_iterator; + typedef std::map::const_iterator property_const_iterator; + + private: + cdef_class_rep (const cdef_class_rep& c) + : cdef_meta_object_rep (c), directory (c.directory), + method_map (c.method_map), property_map (c.property_map), + member_count (c.member_count), handle_class (c.handle_class), + implicit_ctor_list (c.implicit_ctor_list), + object_count (c.object_count), meta (c.meta) { } + }; + +public: + // Create and invalid class object + cdef_class (void) + : cdef_meta_object () { } + + cdef_class (const std::string& nm, + const std::list& superclasses) + : cdef_meta_object (new cdef_class_rep (superclasses)) + { get_rep ()->set_name (nm); } + + cdef_class (const cdef_class& cls) + : cdef_meta_object (cls) { } + + cdef_class (const cdef_object& obj) + : cdef_meta_object (obj) + { + // This should never happen... + if (! is_class ()) + error ("internal error: invalid assignment from %s to meta.class object", + class_name ().c_str ()); + } + + cdef_class& operator = (const cdef_class& cls) + { + cdef_object::operator= (cls); + + return *this; + } + + cdef_method find_method (const std::string& nm, bool local = false); + + void install_method (const cdef_method& meth) + { get_rep ()->install_method (meth); } + + Cell get_methods (void) { return get_rep ()->get_methods (); } + + cdef_property find_property (const std::string& nm); + + void install_property (const cdef_property& prop) + { get_rep ()->install_property (prop); } + + Cell get_properties (void) { return get_rep ()->get_properties (); } + + string_vector get_names (void) { return get_rep ()->get_names (); } + + bool is_abstract (void) const { return get_rep ()->is_abstract (); } + + bool is_sealed (void) const { return get_rep ()->is_sealed (); } + + void set_directory (const std::string& dir) + { get_rep ()->set_directory (dir); } + + std::string get_directory (void) const + { return get_rep ()->get_directory (); } + + std::string get_name (void) const + { return get_rep ()->get_name (); } + + bool is_builtin (void) const + { return get_directory ().empty (); } + + void delete_object (cdef_object obj) + { get_rep ()->delete_object (obj); } + + static cdef_class make_meta_class (tree_classdef* t); + + octave_function* get_method_function (const std::string& nm); + + octave_function* get_constructor_function (void) + { return get_method_function (get_name ()); } + + octave_value construct (const octave_value_list& args) + { return get_rep ()->construct (args); } + + cdef_object construct_object (const octave_value_list& args) + { return get_rep ()->construct_object (args); } + + void initialize_object (cdef_object& obj) + { get_rep ()->initialize_object (obj); } + + void run_constructor (cdef_object& obj, const octave_value_list& args) + { get_rep ()->run_constructor (obj, args); } + + void mark_as_handle_class (void) + { get_rep ()->mark_as_handle_class (); } + + bool is_handle_class (void) const + { return get_rep ()->is_handle_class (); } + + void mark_as_meta_class (void) { get_rep ()->mark_as_meta_class (); } + + bool is_meta_class (void) const { return get_rep ()->is_meta_class (); } + + static const cdef_class& meta_class (void) { return _meta_class; } + static const cdef_class& meta_property (void) { return _meta_property; } + static const cdef_class& meta_method (void) { return _meta_method; } + static const cdef_class& meta_package (void) { return _meta_package; } + + void register_object (void) { get_rep ()->register_object (); } + + void unregister_object (void) { get_rep ()->unregister_object (); } + +private: + cdef_class_rep* get_rep (void) + { return dynamic_cast (cdef_object::get_rep ()); } + + const cdef_class_rep* get_rep (void) const + { return dynamic_cast (cdef_object::get_rep ()); } + + friend bool operator == (const cdef_class&, const cdef_class&); + friend bool operator != (const cdef_class&, const cdef_class&); + friend bool operator < (const cdef_class&, const cdef_class&); + +private: + static cdef_class _meta_class; + static cdef_class _meta_property; + static cdef_class _meta_method; + static cdef_class _meta_package; + + friend void install_classdef (void); +}; + +inline bool +operator == (const cdef_class& clsa, const cdef_class& clsb) +// FIXME: is this really the right way to check class equality? +{ return (clsa.get_rep () == clsb.get_rep ()); } + +inline bool +operator != (const cdef_class& clsa, const cdef_class& clsb) +{ return ! (clsa == clsb); } + +// This is only to be able to use cdef_class as map keys. +inline bool +operator < (const cdef_class& clsa, const cdef_class& clsb) +{ return clsa.get_rep () < clsb.get_rep (); } + +class +cdef_property : public cdef_meta_object +{ + friend class cdef_class; + +private: + + class + cdef_property_rep : public cdef_meta_object_rep + { + public: + cdef_property_rep (void) + : cdef_meta_object_rep () { } + + cdef_object_rep* copy (void) const { return new cdef_property_rep (*this); } + + bool is_property (void) const { return true; } + + std::string get_name (void) const { return get("Name").string_value (); } + + void set_name (const std::string& nm) { put ("Name", nm); } + + bool is_constant (void) const { return get("Constant").bool_value (); } + + octave_value get_value (bool do_check_access = true, + const std::string& who = std::string ()); + + octave_value get_value (const cdef_object& obj, + bool do_check_access = true, + const std::string& who = std::string ()); + + void set_value (cdef_object& obj, const octave_value& val, + bool do_check_access = true, + const std::string& who = std::string ()); + + bool check_get_access (void) const; + + bool check_set_access (void) const; + + private: + cdef_property_rep (const cdef_property_rep& p) + : cdef_meta_object_rep (p) { } + + bool is_recursive_set (const cdef_object& obj) const; + + cdef_property wrap (void) + { + refcount++; + return cdef_property (this); + } + }; + +public: + cdef_property (void) : cdef_meta_object () { } + + cdef_property (const std::string& nm) + : cdef_meta_object (new cdef_property_rep ()) + { get_rep ()->set_name (nm); } + + cdef_property (const cdef_property& prop) + : cdef_meta_object (prop) { } + + cdef_property (const cdef_object& obj) + : cdef_meta_object (obj) + { + // This should never happen... + if (! is_property ()) + error ("internal error: invalid assignment from %s to meta.property object", + class_name ().c_str ()); + } + + cdef_property& operator = (const cdef_property& prop) + { + cdef_object::operator= (prop); + + return *this; + } + + octave_value get_value (const cdef_object& obj, bool do_check_access = true, + const std::string& who = std::string ()) + { return get_rep ()->get_value (obj, do_check_access, who); } + + octave_value get_value (bool do_check_access = true, + const std::string& who = std::string ()) + { return get_rep ()->get_value (do_check_access, who); } + + void set_value (cdef_object& obj, const octave_value& val, + bool do_check_access = true, + const std::string& who = std::string ()) + { get_rep ()->set_value (obj, val, do_check_access, who); } + + bool check_get_access (void) const + { return get_rep ()->check_get_access (); } + + bool check_set_access (void) const + { return get_rep ()->check_set_access (); } + + std::string get_name (void) const { return get_rep ()->get_name (); } + + bool is_constant (void) const { return get_rep ()->is_constant (); } + +private: + cdef_property_rep* get_rep (void) + { return dynamic_cast (cdef_object::get_rep ()); } + + const cdef_property_rep* get_rep (void) const + { return dynamic_cast (cdef_object::get_rep ()); } +}; + +class +cdef_method : public cdef_meta_object +{ + friend class cdef_class; + +private: + + class + cdef_method_rep : public cdef_meta_object_rep + { + public: + cdef_method_rep (void) : cdef_meta_object_rep () { } + + cdef_object_rep* copy (void) const { return new cdef_method_rep(*this); } + + bool is_method (void) const { return true; } + + std::string get_name (void) const { return get("Name").string_value (); } + + void set_name (const std::string& nm) { put ("Name", nm); } + + bool is_static (void) const { return get("Static").bool_value (); } + + octave_value get_function (void) const { return function; } + + void set_function (const octave_value& fcn) { function = fcn; } + + bool check_access (void) const; + + octave_value_list execute (const octave_value_list& args, int nargout, + bool do_check_access = true, + const std::string& who = std::string ()); + + octave_value_list execute (const cdef_object& obj, + const octave_value_list& args, int nargout, + bool do_check_access = true, + const std::string& who = std::string ()); + + bool is_constructor (void) const; + + octave_value_list + meta_subsref (const std::string& type, + const std::list& idx, int nargout); + + bool meta_is_postfix_index_handled (char type) const + { return (type == '(' || type == '.'); } + + private: + cdef_method_rep (const cdef_method_rep& m) + : cdef_meta_object_rep (m), function (m.function) { } + + void check_method (void); + + cdef_method wrap (void) + { + refcount++; + return cdef_method (this); + } + + private: + octave_value function; + }; + +public: + cdef_method (void) : cdef_meta_object () { } + + cdef_method (const std::string& nm) + : cdef_meta_object (new cdef_method_rep ()) + { get_rep ()->set_name (nm); } + + cdef_method (const cdef_method& meth) + : cdef_meta_object (meth) { } + + cdef_method (const cdef_object& obj) + : cdef_meta_object (obj) + { + // This should never happen... + if (! is_method ()) + error ("internal error: invalid assignment from %s to meta.method object", + class_name ().c_str ()); + } + + cdef_method& operator = (const cdef_method& meth) + { + cdef_object::operator= (meth); + + return *this; + } + + /* normal invokation */ + octave_value_list execute (const octave_value_list& args, int nargout, + bool do_check_access = true, + const std::string& who = std::string ()) + { return get_rep ()->execute (args, nargout, do_check_access, who); } + + /* dot-invokation: object is pushed as 1st argument */ + octave_value_list execute (const cdef_object& obj, + const octave_value_list& args, int nargout, + bool do_check_access = true, + const std::string& who = std::string ()) + { return get_rep ()->execute (obj, args, nargout, do_check_access, who); } + + bool check_access (void) const { return get_rep ()->check_access (); } + + std::string get_name (void) const { return get_rep ()->get_name (); } + + bool is_static (void) const { return get_rep ()->is_static (); } + + void set_function (const octave_value& fcn) + { get_rep ()->set_function (fcn); } + + octave_value get_function (void) const + { return get_rep ()->get_function (); } + + bool is_constructor (void) const + { return get_rep ()->is_constructor (); } + +private: + cdef_method_rep* get_rep (void) + { return dynamic_cast (cdef_object::get_rep ()); } + + const cdef_method_rep* get_rep (void) const + { return dynamic_cast (cdef_object::get_rep ()); } +}; + +inline cdef_class +cdef_object_rep::get_class (void) const +{ + gripe_invalid_object ("get_class"); + return cdef_class (); +} + +inline std::string +cdef_object_rep::class_name (void) const +{ return get_class ().get_name (); } + +inline cdef_class +cdef_object::get_class (void) const +{ return rep->get_class (); } + +inline cdef_class +cdef_object_base::get_class (void) const +{ return cdef_class (klass); } + +inline void +cdef_object_base::set_class (const cdef_class& cls) +{ + if ((klass.ok () && cls.ok () && cls != get_class ()) + || (klass.ok () && ! cls.ok ()) + || (! klass.ok () && cls.ok ())) + { + unregister_object (); + klass = cls; + register_object (); + } +} + +inline void +cdef_object_base::register_object (void) +{ + if (klass.ok ()) + { + cdef_class cls (get_class ()); + + if (! error_state && cls.ok ()) + cls.register_object (); + } +} + +inline void +cdef_object_base::unregister_object (void) +{ + if (klass.ok ()) + { + cdef_class cls (get_class ()); + + if (! error_state && cls.ok ()) + cls.unregister_object (); + } +} + +inline cdef_object_rep* +cdef_object_base::make_array (void) const +{ + cdef_object_rep* r = new cdef_object_array (); + + r->set_class (get_class ()); + + return r; +} + +inline cdef_method +cdef_class::find_method (const std::string& nm, bool local) +{ return get_rep ()->find_method (nm, local); } + +inline cdef_property +cdef_class::find_property (const std::string& nm) +{ return get_rep ()->find_property (nm); } + +class +cdef_package : public cdef_meta_object +{ + friend class cdef_class; + +private: + + class + cdef_package_rep : public cdef_meta_object_rep + { + public: + cdef_package_rep (void) + : cdef_meta_object_rep (), member_count (0) { } + + ~cdef_package_rep (void) { } + + cdef_object_rep* copy (void) const { return new cdef_package_rep (*this); } + + bool is_package (void) const { return true; } + + std::string get_name (void) const { return get("Name").string_value (); } + + void set_name (const std::string& nm) { put ("Name", nm); } + + void install_class (const cdef_class& cls, const std::string& nm); + + void install_function (const octave_value& fcn, const std::string& nm); + + void install_package (const cdef_package& pack, const std::string& nm); + + Cell get_classes (void) const; + + Cell get_functions (void) const; + + Cell get_packages (void) const; + + octave_idx_type static_count (void) const { return member_count; } + + void destroy (void) + { + if (member_count) + { + refcount++; + cdef_package lock (this); + + member_count = 0; + class_map.clear (); + package_map.clear (); + } + else + delete this; + } + + octave_value_list + meta_subsref (const std::string& type, + const std::list& idx, int nargout); + + void meta_release (void); + + bool meta_is_postfix_index_handled (char type) const + { return (type == '.'); } + + octave_value find (const std::string& nm); + + private: + std::string full_name; + std::map class_map; + std::map function_map; + std::map package_map; + + // The number of registered members in this package (classes, packages). + // This only accounts for the members that back-reference to this package. + octave_idx_type member_count; + + typedef std::map::iterator class_iterator; + typedef std::map::const_iterator class_const_iterator; + typedef std::map::iterator function_iterator; + typedef std::map::const_iterator function_const_iterator; + typedef std::map::iterator package_iterator; + typedef std::map::const_iterator package_const_iterator; + + private: + cdef_package_rep (const cdef_package_rep& p) + : cdef_meta_object_rep (p), full_name (p.full_name), + class_map (p.class_map), function_map (p.function_map), + package_map (p.package_map), member_count (p.member_count) + { } + + cdef_package wrap (void) + { + refcount++; + return cdef_package (this); + } + }; + +public: + cdef_package (void) : cdef_meta_object () { } + + cdef_package (const std::string& nm) + : cdef_meta_object (new cdef_package_rep ()) + { get_rep ()->set_name (nm); } + + cdef_package (const cdef_package& pack) + : cdef_meta_object (pack) { } + + cdef_package (const cdef_object& obj) + : cdef_meta_object (obj) + { + // This should never happen... + if (! is_package ()) + error ("internal error: invalid assignment from %s to meta.package object", + class_name ().c_str ()); + } + + cdef_package& operator = (const cdef_package& pack) + { + cdef_object::operator= (pack); + + return *this; + } + + void install_class (const cdef_class& cls, const std::string& nm) + { get_rep ()->install_class (cls, nm); } + + void install_function (const octave_value& fcn, const std::string& nm) + { get_rep ()->install_function (fcn, nm); } + + void install_package (const cdef_package& pack, const std::string& nm) + { get_rep ()->install_package (pack, nm); } + + Cell get_classes (void) const + { return get_rep ()->get_classes (); } + + Cell get_functions (void) const + { return get_rep ()->get_functions (); } + + Cell get_packages (void) const + { return get_rep ()->get_packages (); } + + std::string get_name (void) const { return get_rep ()->get_name (); } + + octave_value find (const std::string& nm) { return get_rep ()->find (nm); } + + static const cdef_package& meta (void) { return _meta; } + +private: + cdef_package_rep* get_rep (void) + { return dynamic_cast (cdef_object::get_rep ()); } + + const cdef_package_rep* get_rep (void) const + { return dynamic_cast (cdef_object::get_rep ()); } + +private: + static cdef_package _meta; + + friend void install_classdef (void); +}; + +class +octave_classdef : public octave_base_value +{ +public: + octave_classdef (void) + : octave_base_value (), object () { } + + octave_classdef (const cdef_object& obj) + : octave_base_value (), object (obj) { } + + octave_classdef (const octave_classdef& obj) + : octave_base_value (obj), object (obj.object) { } + + octave_base_value* clone (void) const + { return new octave_classdef (object.clone ()); } + + octave_base_value* empty_clone (void) const + { return new octave_classdef (object.empty_clone ()); } + + cdef_object get_object (void) const { return object; } + + cdef_object& get_object_ref (void) { return object; } + + bool is_defined (void) const { return true; } + + bool is_map (void) const { return true; } + + bool print_as_scalar (void) const { return true; } + + void print(std::ostream& os, bool pr_as_read_syntax = false) const + { + // FIXME: should call "display" method + print_raw(os, pr_as_read_syntax); + newline(os); + } + + void print_raw(std::ostream& os, bool /* pr_as_read_syntax */ = false) const + { + if (object.is_array ()) + os << "array (" << object.dims ().str () << ") of " + << object.class_name () << " objects"; + else + os << object.class_name () << " object"; + } + + octave_value_list subsref (const std::string& type, + const std::list& idx, int nargout); + + octave_value subsref (const std::string& type, + const std::list& idx) + { + octave_value_list retval = subsref (type, idx, 1); + return (retval.length () > 0 ? retval(0) : octave_value ()); + } + + octave_value subsref (const std::string& type, + const std::list& idx, + bool auto_add); + + octave_value subsasgn (const std::string& type, + const std::list& idx, + const octave_value& rhs); + + octave_value + undef_subsasgn (const std::string& type, + const std::list& idx, + const octave_value& rhs); + + string_vector map_keys (void) const { return object.map_keys (); } + + dim_vector dims (void) const { return object.dims (); } + +private: + cdef_object object; + +private: + DECLARE_OCTAVE_ALLOCATOR + +public: + int type_id (void) const { return t_id; } + std::string type_name (void) const { return t_name; } + std::string class_name (void) const { return object.class_name (); } + + static int static_type_id (void) { return t_id; } + static std::string static_type_name (void) { return t_name; } + static std::string static_class_name (void) { return ""; } + static void register_type (void); + +private: + static int t_id; + + static const std::string t_name; +}; + +inline octave_value +to_ov (const cdef_object& obj) +{ + if (obj.ok ()) + return octave_value (new octave_classdef (obj)); + else + return octave_value (Matrix ()); +} + +inline octave_value +to_ov (const octave_value& ov) +{ return ov; } + +inline cdef_object +to_cdef (const octave_value& val) +{ + if (val.type_name () == "object") + return dynamic_cast (val.internal_rep ())->get_object (); + else + { + warning ("trying to cast non-object into object"); + return cdef_object (); + } +} + +inline cdef_object& +to_cdef_ref (octave_value& val) +{ + static cdef_object empty; + + if (val.type_name () == "object") + return dynamic_cast (val.internal_rep ())->get_object_ref (); + else + { + warning ("trying to cast non-object into object"); + return empty; + } +} + +inline cdef_object +to_cdef (const cdef_object& obj) +{ return obj; } + +OCTINTERP_API void install_classdef (void); + +class +cdef_manager +{ +public: + + static cdef_class find_class (const std::string& name, + bool error_if_not_found = true, + bool load_if_not_found = true) + { + if (instance_ok ()) + return instance->do_find_class (name, error_if_not_found, + load_if_not_found); + + return cdef_class (); + } + + static octave_function* find_method_symbol (const std::string& method_name, + const std::string& class_name) + { + if (instance_ok ()) + return instance->do_find_method_symbol (method_name, class_name); + + return 0; + } + + static cdef_package find_package (const std::string& name, + bool error_if_not_found = true, + bool load_if_not_found = true) + { + if (instance_ok ()) + return instance->do_find_package (name, error_if_not_found, + load_if_not_found); + + return cdef_package (); + } + + static octave_function* find_package_symbol (const std::string& pack_name) + { + if (instance_ok ()) + return instance->do_find_package_symbol (pack_name); + + return 0; + } + + static void register_class (const cdef_class& cls) + { + if (instance_ok ()) + instance->do_register_class (cls); + } + + static void unregister_class (const cdef_class& cls) + { + if (instance_ok ()) + instance->do_unregister_class (cls); + } + + static void register_package (const cdef_package& pkg) + { + if (instance_ok ()) + instance->do_register_package (pkg); + } + + static void unregister_package (const cdef_package& pkg) + { + if (instance_ok ()) + instance->do_unregister_package (pkg); + } + +private: + + cdef_manager (void) { } + + cdef_manager (const cdef_manager&); + + cdef_manager& operator = (const cdef_manager&); + + ~cdef_manager (void) { } + + static void create_instance (void); + + static bool instance_ok (void) + { + bool retval = true; + + if (! instance) + create_instance (); + + if (! instance) + { + ::error ("unable to create cdef_manager!"); + + retval = false; + } + + return retval; + } + + static void cleanup_instance (void) + { + delete instance; + + instance = 0; + } + + cdef_class do_find_class (const std::string& name, bool error_if_not_found, + bool load_if_not_found); + + octave_function* do_find_method_symbol (const std::string& method_name, + const std::string& class_name); + + cdef_package do_find_package (const std::string& name, + bool error_if_not_found, + bool load_if_not_found); + + octave_function* do_find_package_symbol (const std::string& pack_name); + + void do_register_class (const cdef_class& cls) + { all_classes[cls.get_name ()] = cls; } + + void do_unregister_class (const cdef_class& cls) + { all_classes.erase(cls.get_name ()); } + + void do_register_package (const cdef_package& pkg) + { all_packages[pkg.get_name ()] = pkg; } + + void do_unregister_package (const cdef_package& pkg) + { all_packages.erase(pkg.get_name ()); } + +private: + + // The single cdef_manager instance + static cdef_manager *instance; + + // All registered/loaded classes + std::map all_classes; + + // All registered/loaded packages + std::map all_packages; +}; + +#endif + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; End: *** +*/ diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/octave-value/ov-fcn-handle.cc --- a/libinterp/octave-value/ov-fcn-handle.cc Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/octave-value/ov-fcn-handle.cc Thu Dec 05 12:04:40 2013 -0500 @@ -270,7 +270,7 @@ std::string dir_name = str.substr (0, xpos); octave_function *xfcn - = load_fcn_from_file (str, dir_name, "", nm); + = load_fcn_from_file (str, dir_name, "", "", nm); if (xfcn) { @@ -300,7 +300,7 @@ std::string dir_name = str.substr (0, xpos); - octave_function *xfcn = load_fcn_from_file (str, dir_name, "", nm); + octave_function *xfcn = load_fcn_from_file (str, dir_name, "", "", nm); if (xfcn) { @@ -323,7 +323,7 @@ std::string dir_name = fpath.substr (0, xpos); - octave_function *xfcn = load_fcn_from_file (fpath, dir_name, "", nm); + octave_function *xfcn = load_fcn_from_file (fpath, dir_name, "", "", nm); if (xfcn) { diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/octave-value/ov-fcn.h --- a/libinterp/octave-value/ov-fcn.h Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/octave-value/ov-fcn.h Thu Dec 05 12:04:40 2013 -0500 @@ -85,6 +85,10 @@ virtual bool is_class_constructor (const std::string& = std::string ()) const { return false; } + virtual bool + is_classdef_constructor (const std::string& = std::string ()) const + { return false; } + virtual bool is_class_method (const std::string& = std::string ()) const { return false; } @@ -160,6 +164,9 @@ virtual void accept (tree_walker&) { } + virtual bool is_postfix_index_handled (char type) const + { return (type == '(' || type == '{'); } + protected: octave_function (const std::string& nm, diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/octave-value/ov-usr-fcn.cc --- a/libinterp/octave-value/ov-usr-fcn.cc Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/octave-value/ov-usr-fcn.cc Thu Dec 05 12:04:40 2013 -0500 @@ -203,7 +203,7 @@ num_named_args (param_list ? param_list->length () : 0), subfunction (false), inline_function (false), anonymous_function (false), nested_function (false), - class_constructor (false), class_method (false), + class_constructor (none), class_method (false), parent_scope (-1), local_scope (sid), curr_unwind_protect_frame (0) #ifdef HAVE_LLVM @@ -470,7 +470,7 @@ octave_value_list octave_user_function::do_multi_index_op (int nargout, - const octave_value_list& args, + const octave_value_list& _args, const std::list* lvalue_list) { octave_value_list retval; @@ -481,6 +481,23 @@ if (! cmd_list) return retval; + // If this function is a classdef constructor, extract the first input + // argument, which must be the partially constructed object instance. + + octave_value_list args (_args); + octave_value_list ret_args; + + if (is_classdef_constructor ()) + { + if (args.length () > 0) + { + ret_args = args.slice (0, 1, true); + args = args.slice (1, args.length () - 1, true); + } + else + panic_impossible (); + } + #ifdef HAVE_LLVM if (is_special_expr () && tree_jit::execute (*this, args, retval)) @@ -524,6 +541,25 @@ return retval; } + // For classdef constructor, pre-populate the output arguments + // with the pre-initialized object instance, extracted above. + + if (is_classdef_constructor ()) + { + if (ret_list) + { + ret_list->define_from_arg_vector (ret_args); + if (error_state) + return retval; + } + else + { + ::error ("%s: invalid classdef constructor, no output argument defined", + dispatch_class ().c_str ()); + return retval; + } + } + // Force parameter list to be undefined when this function exits. // Doing so decrements the reference counts on the values of local // variables that are also named function parameters. diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/octave-value/ov-usr-fcn.h --- a/libinterp/octave-value/ov-usr-fcn.h Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/octave-value/ov-usr-fcn.h Thu Dec 05 12:04:40 2013 -0500 @@ -327,12 +327,20 @@ void mark_as_nested_function (void) { nested_function = true; } - void mark_as_class_constructor (void) { class_constructor = true; } + void mark_as_class_constructor (void) { class_constructor = legacy; } + + void mark_as_classdef_constructor (void) { class_constructor = classdef; } bool is_class_constructor (const std::string& cname = std::string ()) const { - return class_constructor - ? (cname.empty () ? true : cname == dispatch_class ()) : false; + return class_constructor == legacy + ? (cname.empty () ? true : cname == dispatch_class ()) : false; + } + + bool is_classdef_constructor (const std::string& cname = std::string ()) const + { + return class_constructor == classdef + ? (cname.empty () ? true : cname == dispatch_class ()) : false; } void mark_as_class_method (void) { class_method = true; } @@ -408,6 +416,13 @@ private: + enum class_ctor_type + { + none, + legacy, + classdef + }; + // List of arguments for this function. These are local variables. tree_parameter_list *param_list; @@ -470,8 +485,8 @@ // TRUE means this is a nested function. (either a child or parent) bool nested_function; - // TRUE means this function is the constructor for class object. - bool class_constructor; + // Enum describing whether this function is the constructor for class object. + class_ctor_type class_constructor; // TRUE means this function is a method for a class. bool class_method; diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/octave-value/ov.cc --- a/libinterp/octave-value/ov.cc Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/octave-value/ov.cc Thu Dec 05 12:04:40 2013 -0500 @@ -65,6 +65,7 @@ #include "ov-range.h" #include "ov-struct.h" #include "ov-class.h" +#include "ov-classdef.h" #include "ov-oncleanup.h" #include "ov-cs-list.h" #include "ov-colon.h" diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/octave.cc --- a/libinterp/octave.cc Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/octave.cc Thu Dec 05 12:04:40 2013 -0500 @@ -68,6 +68,7 @@ #include "ops.h" #include "options-usage.h" #include "ov.h" +#include "ov-classdef.h" #include "ov-range.h" #include "toplev.h" #include "parse.h" @@ -752,6 +753,8 @@ install_builtins (); + install_classdef (); + for (std::list::const_iterator it = command_line_path.begin (); it != command_line_path.end (); it++) load_path::set_command_line_path (*it); diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/lex.h --- a/libinterp/parse-tree/lex.h Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/parse-tree/lex.h Thu Dec 05 12:04:40 2013 -0500 @@ -261,7 +261,9 @@ looking_at_matrix_or_assign_lhs (false), looking_for_object_index (false), looking_at_indirect_ref (false), parsing_class_method (false), - maybe_classdef_get_set_method (false), parsing_classdef (false), + parsing_classdef (false), maybe_classdef_get_set_method (false), + parsing_classdef_get_method (false), + parsing_classdef_set_method (false), quote_is_transpose (false), force_script (false), reading_fcn_file (false), reading_script_file (false), reading_classdef_file (false), @@ -341,13 +343,19 @@ // true means we are parsing a class method in function or classdef file. bool parsing_class_method; + // true means we are parsing a classdef file + bool parsing_classdef; + // true means we are parsing a class method declaration line in a // classdef file and can accept a property get or set method name. // for example, "get.propertyname" is recognized as a function name. bool maybe_classdef_get_set_method; - // true means we are parsing a classdef file - bool parsing_classdef; + // TRUE means we are parsing a classdef get.method. + bool parsing_classdef_get_method; + + // TRUE means we are parsing a classdef set.method. + bool parsing_classdef_set_method; // return transpose or start a string? bool quote_is_transpose; diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/lex.ll --- a/libinterp/parse-tree/lex.ll Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/parse-tree/lex.ll Thu Dec 05 12:04:40 2013 -0500 @@ -1067,7 +1067,7 @@ { curr_lexer->looking_for_object_index = true; - return curr_lexer->count_token_internal (SUPERCLASSREF); + return curr_lexer->count_token_internal (id_tok); } } } @@ -1094,7 +1094,7 @@ { curr_lexer->looking_for_object_index = true; - return curr_lexer->count_token_internal (METAQUERY); + return curr_lexer->count_token_internal (id_tok); } } } @@ -1824,8 +1824,10 @@ looking_for_object_index = false; looking_at_indirect_ref = false; parsing_class_method = false; + parsing_classdef = false; maybe_classdef_get_set_method = false; - parsing_classdef = false; + parsing_classdef_get_method = false; + parsing_classdef_set_method = false; force_script = false; reading_fcn_file = false; reading_script_file = false; @@ -2579,36 +2581,30 @@ int octave_base_lexer::handle_superclass_identifier (void) { - std::string pkg; - char *yytxt = flex_yytext (); - std::string meth = strip_trailing_whitespace (yytxt); + std::string meth = flex_yytext (); + size_t pos = meth.find ("@"); - std::string cls = meth.substr (pos).substr (1); - meth = meth.substr (0, pos - 1); - + std::string cls = meth.substr (pos + 1); + meth = meth.substr (0, pos); + + std::string pkg; pos = cls.find ("."); if (pos != std::string::npos) { - pkg = cls.substr (pos).substr (1); - cls = cls.substr (0, pos - 1); + pkg = cls.substr (0, pos); + cls = cls.substr (pos + 1); } int kw_token = (is_keyword_token (meth) || is_keyword_token (cls) || is_keyword_token (pkg)); if (kw_token) { - error ("method, class and package names may not be keywords"); + error ("method, class, and package names may not be keywords"); return LEXICAL_ERROR; } - symbol_table::scope_id sid = symtab_context.curr_scope (); - - push_token (new token - (SUPERCLASSREF, - meth.empty () ? 0 : &(symbol_table::insert (meth, sid)), - cls.empty () ? 0 : &(symbol_table::insert (cls, sid)), - pkg.empty () ? 0 : &(symbol_table::insert (pkg, sid)), - input_line_number, current_input_column)); + push_token (new token (SUPERCLASSREF, meth, pkg, cls, + input_line_number, current_input_column)); current_input_column += flex_yyleng (); @@ -2618,31 +2614,25 @@ int octave_base_lexer::handle_meta_identifier (void) { + std::string cls = std::string(flex_yytext ()).substr (1); + std::string pkg; - char *yytxt = flex_yytext (); - std::string cls = strip_trailing_whitespace (yytxt).substr (1); size_t pos = cls.find ("."); - if (pos != std::string::npos) { - pkg = cls.substr (pos).substr (1); - cls = cls.substr (0, pos - 1); + pkg = cls.substr (0, pos); + cls = cls.substr (pos + 1); } int kw_token = is_keyword_token (cls) || is_keyword_token (pkg); if (kw_token) { - error ("class and package names may not be keywords"); + error ("class and package names may not be keywords"); return LEXICAL_ERROR; } - symbol_table::scope_id sid = symtab_context.curr_scope (); - - push_token (new token - (METAQUERY, - cls.empty () ? 0 : &(symbol_table::insert (cls, sid)), - pkg.empty () ? 0 : &(symbol_table::insert (pkg, sid)), - input_line_number, current_input_column)); + push_token (new token (METAQUERY, pkg, cls, input_line_number, + current_input_column)); current_input_column += flex_yyleng (); diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/module.mk --- a/libinterp/parse-tree/module.mk Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/parse-tree/module.mk Thu Dec 05 12:04:40 2013 -0500 @@ -21,6 +21,7 @@ parse-tree/pt-cbinop.h \ parse-tree/pt-cell.h \ parse-tree/pt-check.h \ + parse-tree/pt-classdef.h \ parse-tree/pt-cmd.h \ parse-tree/pt-colon.h \ parse-tree/pt-const.h \ @@ -29,6 +30,7 @@ parse-tree/pt-except.h \ parse-tree/pt-exp.h \ parse-tree/pt-fcn-handle.h \ + parse-tree/pt-funcall.h \ parse-tree/pt-id.h \ parse-tree/pt-idx.h \ parse-tree/pt-jump.h \ @@ -52,6 +54,7 @@ parse-tree/pt-cbinop.cc \ parse-tree/pt-cell.cc \ parse-tree/pt-check.cc \ + parse-tree/pt-classdef.cc \ parse-tree/pt-cmd.cc \ parse-tree/pt-colon.cc \ parse-tree/pt-const.cc \ @@ -60,6 +63,7 @@ parse-tree/pt-except.cc \ parse-tree/pt-exp.cc \ parse-tree/pt-fcn-handle.cc \ + parse-tree/pt-funcall.cc \ parse-tree/pt-id.cc \ parse-tree/pt-idx.cc \ parse-tree/pt-jump.cc \ diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/oct-parse.in.yy --- a/libinterp/parse-tree/oct-parse.in.yy Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/parse-tree/oct-parse.in.yy Thu Dec 05 12:04:40 2013 -0500 @@ -62,6 +62,7 @@ #include "load-path.h" #include "oct-hist.h" #include "oct-map.h" +#include "ov-classdef.h" #include "ov-fcn-handle.h" #include "ov-usr-fcn.h" #include "ov-null-mat.h" @@ -70,6 +71,7 @@ #include "parse.h" #include "pt-all.h" #include "pt-eval.h" +#include "pt-funcall.h" #include "symtab.h" #include "token.h" #include "unwind-prot.h" @@ -164,6 +166,8 @@ tree_expression *tree_expression_type; tree_constant *tree_constant_type; tree_fcn_handle *tree_fcn_handle_type; + tree_funcall *tree_funcall_type; + tree_function_def *tree_function_def_type; tree_anon_fcn_handle *tree_anon_fcn_handle_type; tree_identifier *tree_identifier_type; tree_index_expression *tree_index_expression_type; @@ -183,7 +187,24 @@ tree_statement *tree_statement_type; tree_statement_list *tree_statement_list_type; octave_user_function *octave_user_function_type; - void *dummy_type; + + tree_classdef *tree_classdef_type; + tree_classdef_attribute* tree_classdef_attribute_type; + tree_classdef_attribute_list* tree_classdef_attribute_list_type; + tree_classdef_superclass* tree_classdef_superclass_type; + tree_classdef_superclass_list* tree_classdef_superclass_list_type; + tree_classdef_body* tree_classdef_body_type; + tree_classdef_property* tree_classdef_property_type; + tree_classdef_property_list* tree_classdef_property_list_type; + tree_classdef_properties_block* tree_classdef_properties_block_type; + tree_classdef_methods_list* tree_classdef_methods_list_type; + tree_classdef_methods_block* tree_classdef_methods_block_type; + tree_classdef_event* tree_classdef_event_type; + tree_classdef_events_list* tree_classdef_events_list_type; + tree_classdef_events_block* tree_classdef_events_block_type; + tree_classdef_enum* tree_classdef_enum_type; + tree_classdef_enum_list* tree_classdef_enum_list_type; + tree_classdef_enum_block* tree_classdef_enum_block_type; } // Tokens with line and column information. @@ -210,6 +231,7 @@ %token TRY CATCH %token GLOBAL PERSISTENT %token FCN_HANDLE +%token CLASSDEF %token PROPERTIES METHODS EVENTS ENUMERATION %token METAQUERY %token SUPERCLASSREF @@ -218,13 +240,12 @@ // Other tokens. %token END_OF_INPUT LEXICAL_ERROR -%token INPUT_FILE CLASSDEF +%token INPUT_FILE // %token VARARGIN VARARGOUT // Nonterminals we construct. -%type function_beg -%type stash_comment classdef_beg -%type properties_beg methods_beg events_beg enum_beg +%type stash_comment +%type function_beg classdef_beg %type sep_no_nl opt_sep_no_nl nl opt_nl sep opt_sep %type input %type string constant magic_colon @@ -236,18 +257,19 @@ %type primary_expr oper_expr power_expr %type simple_expr colon_expr assign_expr expression %type identifier fcn_name magic_tilde -%type superclass_identifier meta_identifier -%type function1 function2 classdef1 +%type superclass_identifier meta_identifier +%type function1 function2 %type word_list_cmd %type colon_expr1 %type arg_list word_list assign_lhs %type cell_or_matrix_row %type param_list param_list1 param_list2 %type return_list return_list1 -%type superclasses opt_superclasses %type command select_command loop_command -%type jump_command except_command function -%type file classdef +%type jump_command except_command +%type function +%type classdef +%type file %type if_command %type elseif_clause else_clause %type if_cmd_list1 if_cmd_list @@ -257,25 +279,25 @@ %type decl2 param_list_elt %type decl1 %type declaration -%type statement function_end classdef_end +%type statement function_end %type simple_list simple_list1 list list1 %type opt_list -// These types need to be specified. -%type attr -%type class_event -%type class_enum -%type class_property -%type properties_list -%type properties_block -%type methods_list -%type methods_block -%type opt_attr_list -%type attr_list -%type events_list -%type events_block -%type enum_list -%type enum_block -%type class_body +%type attr +%type attr_list opt_attr_list +%type superclass +%type superclass_list opt_superclass_list +%type class_body +%type class_property +%type property_list +%type properties_block +%type methods_list +%type methods_block +%type class_event +%type events_list +%type events_block +%type class_enum +%type enum_list +%type enum_block // Precedence and associativity. %right '=' ADD_EQ SUB_EQ MUL_EQ DIV_EQ LEFTDIV_EQ POW_EQ EMUL_EQ EDIV_EQ ELEFTDIV_EQ EPOW_EQ OR_EQ AND_EQ LSHIFT_EQ RSHIFT_EQ @@ -439,11 +461,26 @@ superclass_identifier : SUPERCLASSREF - { $$ = new tree_identifier ($1->line (), $1->column ()); } + { + std::string method_nm = $1->superclass_method_name (); + std::string package_nm = $1->superclass_package_name (); + std::string class_nm = $1->superclass_class_name (); + + $$ = parser.make_superclass_ref + (method_nm, package_nm, class_nm, + $1->line (), $1->column ()); + } ; meta_identifier : METAQUERY - { $$ = new tree_identifier ($1->line (), $1->column ()); } + { + std::string package_nm = $1->meta_package_name (); + std::string class_nm = $1->meta_class_name (); + + $$ = parser.make_meta_class_query + (package_nm, class_nm, + $1->line (), $1->column ()); + } ; string : DQ_STRING @@ -867,8 +904,6 @@ { $$ = $1; } | file { $$ = $1; } - | classdef - { $$ = $1; } ; // ===================== @@ -1294,6 +1329,13 @@ $$ = 0; } + | INPUT_FILE opt_nl classdef opt_sep END_OF_INPUT + { + if (lexer.reading_classdef_file) + parser.classdef_object = $3; + + $$ = 0; + } ; // =================== @@ -1336,12 +1378,14 @@ { lexer.parsed_function_name.top () = true; lexer.maybe_classdef_get_set_method = false; + lexer.parsing_classdef_get_method = true; $$ = $3; } | SET '.' identifier { lexer.parsed_function_name.top () = true; lexer.maybe_classdef_get_set_method = false; + lexer.parsing_classdef_set_method = true; $$ = $3; } ; @@ -1352,6 +1396,11 @@ delete $1; + if (lexer.parsing_classdef_get_method) + fname.insert (0, "get."); + else if (lexer.parsing_classdef_set_method) + fname.insert (0, "set."); + $$ = parser.frob_function (fname, $2); } ; @@ -1411,158 +1460,217 @@ // Classdef // ======== -classdef_beg : CLASSDEF stash_comment +classdef_beg : CLASSDEF { - $$ = 0; + if (! lexer.reading_classdef_file) + { + parser.bison_error ("classdef must appear inside a file containing only a class definition"); + YYABORT; + } + lexer.parsing_classdef = true; + $$ = $1; } ; -classdef_end : END +classdef : classdef_beg stash_comment opt_attr_list identifier opt_superclass_list opt_sep class_body opt_sep END { lexer.parsing_classdef = false; - if (parser.end_token_ok ($1, token::classdef_end)) - $$ = parser.make_end ("endclassdef", false, - $1->line (), $1->column ()); - else - ABORT_PARSE; + if (! ($$ = parser.make_classdef ($1, $3, $4, $5, $7, $9, $2))) + { + // make_classdef deleted $3, $4, $5, and $7. + ABORT_PARSE; + } } ; -classdef1 : classdef_beg opt_attr_list identifier opt_superclasses - { $$ = 0; } - ; - -classdef : classdef1 opt_sep class_body opt_sep stash_comment classdef_end - { $$ = 0; } - ; - opt_attr_list : // empty { $$ = 0; } | '(' attr_list ')' - { $$ = 0; } + { $$ = $2; } ; attr_list : attr - { $$ = 0; } + { $$ = new tree_classdef_attribute_list ($1); } | attr_list ',' attr - { $$ = 0; } + { + $1->append ($3); + $$ = $1; + } ; attr : identifier - { $$ = 0; } + { $$ = new tree_classdef_attribute ($1); } | identifier '=' decl_param_init expression - { $$ = 0; } + { + lexer.looking_at_initializer_expression = false; + $$ = new tree_classdef_attribute ($1, $4); + } | EXPR_NOT identifier - { $$ = 0; } + { $$ = new tree_classdef_attribute ($2, false); } ; -opt_superclasses +opt_superclass_list : // empty { $$ = 0; } - | superclasses - { $$ = 0; } + | superclass_list + { $$ = $1; } ; -superclasses : EXPR_LT identifier '.' identifier - { $$ = 0; } - | EXPR_LT identifier - { $$ = 0; } - | superclasses EXPR_AND identifier '.' identifier - { $$ = 0; } - | superclasses EXPR_AND identifier - { $$ = 0; } +superclass_list : EXPR_LT superclass + { $$ = new tree_classdef_superclass_list ($2); } + | superclass_list EXPR_AND superclass + { + $1->append ($3); + $$ = $1; + } + ; + +superclass : identifier + { $$ = new tree_classdef_superclass ($1); } + | identifier '.' identifier + { $$ = new tree_classdef_superclass ($3, $1); } ; class_body : properties_block - { $$ = 0; } + { $$ = new tree_classdef_body ($1); } | methods_block - { $$ = 0; } + { $$ = new tree_classdef_body ($1); } | events_block - { $$ = 0; } + { $$ = new tree_classdef_body ($1); } | enum_block - { $$ = 0; } + { $$ = new tree_classdef_body ($1); } | class_body opt_sep properties_block - { $$ = 0; } + { + $1->append ($3); + $$ = $1; + } | class_body opt_sep methods_block - { $$ = 0; } + { + $1->append ($3); + $$ = $1; + } | class_body opt_sep events_block - { $$ = 0; } + { + $1->append ($3); + $$ = $1; + } | class_body opt_sep enum_block - { $$ = 0; } - ; - -properties_beg : PROPERTIES stash_comment - { $$ = 0; } + { + $1->append ($3); + $$ = $1; + } ; properties_block - : properties_beg opt_attr_list opt_sep properties_list opt_sep END - { $$ = 0; } + : PROPERTIES stash_comment opt_attr_list opt_sep property_list opt_sep END + { + if (! ($$ = parser.make_classdef_properties_block + ($1, $3, $5, $7, $2))) + { + // make_classdef_properties_block delete $3 and $5. + ABORT_PARSE; + } + } ; -properties_list +property_list : class_property - { $$ = 0; } - | properties_list opt_sep class_property - { $$ = 0; } + { $$ = new tree_classdef_property_list ($1); } + | property_list opt_sep class_property + { + $1->append ($3); + $$ = $1; + } ; class_property : identifier - { $$ = 0; } + { $$ = new tree_classdef_property ($1); } | identifier '=' decl_param_init expression ';' - { $$ = 0; } + { + lexer.looking_at_initializer_expression = false; + $$ = new tree_classdef_property ($1, $4); + } ; -methods_beg : METHODS stash_comment - { $$ = 0; } - ; - -methods_block : methods_beg opt_attr_list opt_sep methods_list opt_sep END - { $$ = 0; } +methods_block : METHODS stash_comment opt_attr_list opt_sep methods_list opt_sep END + { + if (! ($$ = parser.make_classdef_methods_block + ($1, $3, $5, $7, $2))) + { + // make_classdef_methods_block deleted $3 and $5. + ABORT_PARSE; + } + } ; methods_list : function - { $$ = 0; } + { + octave_value fcn; + if ($1) + fcn = $1->function (); + delete $1; + $$ = new tree_classdef_methods_list (fcn); + } | methods_list opt_sep function - { $$ = 0; } + { + octave_value fcn; + if ($3) + fcn = $3->function (); + delete $3; + + $1->append (fcn); + $$ = $1; + } ; -events_beg : EVENTS stash_comment - { $$ = 0; } - ; - -events_block : events_beg opt_attr_list opt_sep events_list opt_sep END - { $$ = 0; } +events_block : EVENTS stash_comment opt_attr_list opt_sep events_list opt_sep END + { + if (! ($$ = parser.make_classdef_events_block + ($1, $3, $5, $7, $2))) + { + // make_classdef_events_block deleted $3 and $5. + ABORT_PARSE; + } + } ; events_list : class_event - { $$ = 0; } + { $$ = new tree_classdef_events_list ($1); } | events_list opt_sep class_event - { $$ = 0; } + { + $1->append ($3); + $$ = $1; + } ; class_event : identifier - { $$ = 0; } + { $$ = new tree_classdef_event ($1); } ; -enum_beg : ENUMERATION stash_comment - { $$ = 0; } - ; - -enum_block : enum_beg opt_attr_list opt_sep enum_list opt_sep END - { $$ = 0; } +enum_block : ENUMERATION stash_comment opt_attr_list opt_sep enum_list opt_sep END + { + if (! ($$ = parser.make_classdef_enum_block + ($1, $3, $5, $7, $2))) + { + // make_classdef_enum_block deleted $3 and $5. + ABORT_PARSE; + } + } ; enum_list : class_enum - { $$ = 0; } + { $$ = new tree_classdef_enum_list ($1); } | enum_list opt_sep class_enum - { $$ = 0; } + { + $1->append ($3); + $$ = $1; + } ; class_enum : identifier '(' expression ')' - { $$ = 0; } + { $$ = new tree_classdef_enum ($1, $3); } ; // ============= @@ -1660,6 +1768,7 @@ curr_fcn_depth = 0; primary_fcn_scope = -1; curr_class_name = ""; + curr_package_name = ""; function_scopes.clear (); primary_fcn_ptr = 0; subfunction_names.clear (); @@ -3002,6 +3111,197 @@ lexer.looking_at_parameter_list = false; } +tree_funcall * +octave_base_parser::make_superclass_ref (const std::string& method_nm, + const std::string& package_nm, + const std::string& class_nm, + int l, int c) +{ + octave_value_list args; + + args(2) = class_nm; + args(1) = package_nm; + args(0) = method_nm; + + octave_value fcn + = symbol_table::find_built_in_function ("__superclass_reference__"); + + return new tree_funcall (fcn, args); +} + +tree_funcall * +octave_base_parser::make_meta_class_query (const std::string& package_nm, + const std::string& class_nm, + int l, int c) +{ + octave_value_list args; + + args(1) = class_nm; + args(0) = package_nm; + + octave_value fcn + = symbol_table::find_built_in_function ("__meta_class_query__"); + + return new tree_funcall (fcn, args); +} + +// A CLASSDEF block defines a class that has a constructor and other +// methods, but it is not an executable command. Parsing the block +// makes some changes in the symbol table (inserting the constructor +// and methods, and adding to the list of known objects) and creates +// a parse tree containing meta information about the class. + +tree_classdef * +octave_base_parser::make_classdef (token *tok_val, + tree_classdef_attribute_list *a, + tree_identifier *id, + tree_classdef_superclass_list *sc, + tree_classdef_body *body, token *end_tok, + octave_comment_list *lc) +{ + tree_classdef *retval = 0; + + std::string cls_name = id->name (); + + std::string nm = lexer.fcn_file_name; + + size_t pos = nm.find_last_of (file_ops::dir_sep_chars ()); + + if (pos != std::string::npos) + nm = lexer.fcn_file_name.substr (pos+1); + + if (nm != cls_name) + bison_error ("invalid classdef definition, the class name must match the file name"); + else if (end_token_ok (end_tok, token::classdef_end)) + { + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + retval = new tree_classdef (a, id, sc, body, lc, tc, + curr_package_name, l, c); + } + + if (! retval) + { + delete a; + delete id; + delete sc; + delete body; + } + + return retval; +} + +tree_classdef_properties_block * +octave_base_parser::make_classdef_properties_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_property_list *plist, + token *end_tok, + octave_comment_list *lc) +{ + tree_classdef_properties_block *retval = 0; + + if (end_token_ok (end_tok, token::properties_end)) + { + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + retval = new tree_classdef_properties_block (a, plist, lc, tc, l, c); + } + else + { + delete a; + delete plist; + } + + return retval; +} + +tree_classdef_methods_block * +octave_base_parser::make_classdef_methods_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_methods_list *mlist, + token *end_tok, + octave_comment_list *lc) +{ + tree_classdef_methods_block *retval = 0; + + if (end_token_ok (end_tok, token::methods_end)) + { + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + retval = new tree_classdef_methods_block (a, mlist, lc, tc, l, c); + } + else + { + delete a; + delete mlist; + } + + return retval; +} + +tree_classdef_events_block * +octave_base_parser::make_classdef_events_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_events_list *elist, + token *end_tok, + octave_comment_list *lc) +{ + tree_classdef_events_block *retval = 0; + + if (end_token_ok (end_tok, token::events_end)) + { + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + retval = new tree_classdef_events_block (a, elist, lc, tc, l, c); + } + else + { + delete a; + delete elist; + } + + return retval; +} + +tree_classdef_enum_block * +octave_base_parser::make_classdef_enum_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_enum_list *elist, + token *end_tok, + octave_comment_list *lc) +{ + tree_classdef_enum_block *retval = 0; + + if (end_token_ok (end_tok, token::enumeration_end)) + { + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + retval = new tree_classdef_enum_block (a, elist, lc, tc, l, c); + } + else + { + delete a; + delete elist; + } + + return retval; +} + // Make an index expression. tree_index_expression * @@ -3024,7 +3324,8 @@ int l = expr->line (); int c = expr->column (); - expr->mark_postfix_indexed (); + if (! expr->is_postfix_indexed ()) + expr->set_postfix_index (type); if (expr->is_index_expression ()) { @@ -3051,6 +3352,9 @@ int l = expr->line (); int c = expr->column (); + if (! expr->is_postfix_indexed ()) + expr->set_postfix_index ('.'); + if (expr->is_index_expression ()) { tree_index_expression *tmp = static_cast (expr); @@ -3070,13 +3374,17 @@ // Make an indirect reference expression with dynamic field name. tree_index_expression * -octave_base_parser::make_indirect_ref (tree_expression *expr, tree_expression *elt) +octave_base_parser::make_indirect_ref (tree_expression *expr, + tree_expression *elt) { tree_index_expression *retval = 0; int l = expr->line (); int c = expr->column (); + if (! expr->is_postfix_indexed ()) + expr->set_postfix_index ('.'); + if (expr->is_index_expression ()) { tree_index_expression *tmp = static_cast (expr); @@ -3464,6 +3772,7 @@ static octave_function * parse_fcn_file (const std::string& full_file, const std::string& file, const std::string& dispatch_type, + const std::string& package_name, bool require_file, bool force_script, bool autoload, bool relative_lookup, const std::string& warn_for) { @@ -3497,6 +3806,7 @@ octave_parser parser (ffile); parser.curr_class_name = dispatch_type; + parser.curr_package_name = package_name; parser.autoloading = autoload; parser.fcn_file_from_relative_lookup = relative_lookup; @@ -3511,20 +3821,34 @@ fcn_ptr = parser.primary_fcn_ptr; - if (fcn_ptr) + if (status == 0) { - fcn_ptr->maybe_relocate_end (); - - if (parser.parsing_subfunctions) + if (parser.lexer.reading_classdef_file + && parser.classdef_object) { - if (! parser.endfunction_found) - parser.subfunction_names.reverse (); - - fcn_ptr->stash_subfunction_names (parser.subfunction_names); + // Convert parse tree for classdef object to + // meta.class info (and stash it in the symbol + // table?). Return pointer to constructor? + + if (fcn_ptr) + panic_impossible (); + + fcn_ptr = parser.classdef_object->make_meta_class (); + } + else if (fcn_ptr) + { + fcn_ptr->maybe_relocate_end (); + + if (parser.parsing_subfunctions) + { + if (! parser.endfunction_found) + parser.subfunction_names.reverse (); + + fcn_ptr->stash_subfunction_names (parser.subfunction_names); + } } } - - if (status != 0) + else error ("parse error while reading file %s", full_file.c_str ()); } else if (require_file) @@ -3565,7 +3889,8 @@ symbol_found = true; octave_function *fcn - = parse_fcn_file (full_file, file, "", true, false, false, false, ""); + = parse_fcn_file (full_file, file, "", "", true, false, false, false, + ""); if (fcn) { @@ -3629,6 +3954,7 @@ octave_function * load_fcn_from_file (const std::string& file_name, const std::string& dir_name, const std::string& dispatch_type, + const std::string& package_name, const std::string& fcn_name, bool autoload) { octave_function *retval = 0; @@ -3676,7 +4002,8 @@ // to get the help-string to use. octave_function *tmpfcn = parse_fcn_file (file.substr (0, len - 2), - nm, dispatch_type, false, + nm, dispatch_type, + package_name, false, autoload, autoload, relative_lookup, ""); @@ -3688,8 +4015,8 @@ } else if (len > 2) { - retval = parse_fcn_file (file, nm, dispatch_type, true, autoload, - autoload, relative_lookup, ""); + retval = parse_fcn_file (file, nm, dispatch_type, package_name, true, + autoload, autoload, relative_lookup, ""); } if (retval) @@ -3903,7 +4230,7 @@ if (! error_state) { octave_function *fcn = parse_fcn_file (file_full_name, file_name, - "", require_file, true, + "", "", require_file, true, false, false, warn_for); if (! error_state) @@ -4626,7 +4953,7 @@ if (nargin == 2) octave_stdout << "parsing " << full_file << std::endl; - octave_function *fcn = parse_fcn_file (full_file, file, "", + octave_function *fcn = parse_fcn_file (full_file, file, "", "", true, false, false, false, "__parse_file__"); diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/parse.h --- a/libinterp/parse-tree/parse.h Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/parse-tree/parse.h Thu Dec 05 12:04:40 2013 -0500 @@ -43,6 +43,18 @@ class tree_argument_list; class tree_array_list; class tree_cell; +class tree_classdef; +class tree_classdef_attribute_list; +class tree_classdef_body; +class tree_classdef_enum_block; +class tree_classdef_enum_list; +class tree_classdef_events_block; +class tree_classdef_events_list; +class tree_classdef_methods_block; +class tree_classdef_methods_list; +class tree_classdef_properties_block; +class tree_classdef_property_list; +class tree_classdef_superclass_list; class tree_colon_expression; class tree_command; class tree_constant; @@ -50,6 +62,7 @@ class tree_decl_init_list; class tree_expression; class tree_fcn_handle; +class tree_funcall; class tree_function_def; class tree_identifier; class tree_if_clause; @@ -92,6 +105,7 @@ load_fcn_from_file (const std::string& file_name, const std::string& dir_name = std::string (), const std::string& dispatch_type = std::string (), + const std::string& package_name = std::string (), const std::string& fcn_name = std::string (), bool autoload = false); @@ -136,9 +150,9 @@ autoloading (false), fcn_file_from_relative_lookup (false), parsing_subfunctions (false), max_fcn_depth (0), curr_fcn_depth (0), primary_fcn_scope (-1), - curr_class_name (), function_scopes (), primary_fcn_ptr (0), - subfunction_names (), stmt_list (0), - lexer (lxr) + curr_class_name (), curr_package_name (), function_scopes (), + primary_fcn_ptr (0), subfunction_names (), classdef_object (0), + stmt_list (0), lexer (lxr) { } ~octave_base_parser (void); @@ -284,6 +298,47 @@ void recover_from_parsing_function (void); + tree_funcall * + make_superclass_ref (const std::string& method_nm, + const std::string& package_nm, + const std::string& class_nm, + int l, int c); + + tree_funcall * + make_meta_class_query (const std::string& package_nm, + const std::string& class_nm, + int l, int c); + + tree_classdef * + make_classdef (token *tok_val, tree_classdef_attribute_list *a, + tree_identifier *id, tree_classdef_superclass_list *sc, + tree_classdef_body *body, token *end_tok, + octave_comment_list *lc); + + tree_classdef_properties_block * + make_classdef_properties_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_property_list *plist, + token *end_tok, octave_comment_list *lc); + + tree_classdef_methods_block * + make_classdef_methods_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_methods_list *mlist, + token *end_tok, octave_comment_list *lc); + + tree_classdef_events_block * + make_classdef_events_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_events_list *elist, + token *end_tok, octave_comment_list *lc); + + tree_classdef_enum_block * + make_classdef_enum_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_enum_list *elist, + token *end_tok, octave_comment_list *lc); + // Make an index expression. tree_index_expression * make_index_expression (tree_expression *expr, @@ -372,6 +427,10 @@ // constructors. std::string curr_class_name; + // Name of the current package when we are parsing an element contained + // in a package directory (+-directory). + std::string curr_package_name; + // A stack holding the nested function scopes being parsed. // We don't use std::stack, because we want the clear method. Also, we // must access one from the top @@ -385,6 +444,9 @@ // file. Eventually stashed in the primary function object. std::list subfunction_names; + // Pointer to the classdef object we just parsed, if any. + tree_classdef *classdef_object; + // Result of parsing input. tree_statement_list *stmt_list; diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/pt-all.h --- a/libinterp/parse-tree/pt-all.h Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/parse-tree/pt-all.h Thu Dec 05 12:04:40 2013 -0500 @@ -30,6 +30,7 @@ #include "pt-binop.h" #include "pt-cbinop.h" #include "pt-check.h" +#include "pt-classdef.h" #include "pt-cmd.h" #include "pt-colon.h" #include "pt-const.h" @@ -37,6 +38,7 @@ #include "pt-except.h" #include "pt-exp.h" #include "pt-fcn-handle.h" +#include "pt-funcall.h" #include "pt-id.h" #include "pt-idx.h" #include "pt-jump.h" diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/pt-bp.cc --- a/libinterp/parse-tree/pt-bp.cc Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/parse-tree/pt-bp.cc Thu Dec 05 12:04:40 2013 -0500 @@ -293,6 +293,12 @@ } void +tree_breakpoint::visit_funcall (tree_funcall&) +{ + panic_impossible (); +} + +void tree_breakpoint::visit_parameter_list (tree_parameter_list&) { panic_impossible (); diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/pt-bp.h --- a/libinterp/parse-tree/pt-bp.h Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/parse-tree/pt-bp.h Thu Dec 05 12:04:40 2013 -0500 @@ -106,6 +106,8 @@ void visit_fcn_handle (tree_fcn_handle&); + void visit_funcall (tree_funcall&); + void visit_parameter_list (tree_parameter_list&); void visit_postfix_expression (tree_postfix_expression&); diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/pt-check.cc --- a/libinterp/parse-tree/pt-check.cc Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/parse-tree/pt-check.cc Thu Dec 05 12:04:40 2013 -0500 @@ -357,6 +357,11 @@ } void +tree_checker::visit_funcall (tree_funcall& /* fc */) +{ +} + +void tree_checker::visit_parameter_list (tree_parameter_list& lst) { tree_parameter_list::iterator p = lst.begin (); diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/pt-check.h --- a/libinterp/parse-tree/pt-check.h Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/parse-tree/pt-check.h Thu Dec 05 12:04:40 2013 -0500 @@ -91,6 +91,8 @@ void visit_fcn_handle (tree_fcn_handle&); + void visit_funcall (tree_funcall&); + void visit_parameter_list (tree_parameter_list&); void visit_postfix_expression (tree_postfix_expression&); diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/pt-classdef.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/parse-tree/pt-classdef.cc Thu Dec 05 12:04:40 2013 -0500 @@ -0,0 +1,259 @@ +/* + +Copyright (C) 2012-2013 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "ov-classdef.h" +#include "pt-classdef.h" + +// Classdef attribute + +void +tree_classdef_attribute::accept (tree_walker& tw) +{ + tw.visit_classdef_attribute (*this); +} + +// Classdef attribute_list + +tree_classdef_attribute_list::~tree_classdef_attribute_list (void) +{ + while (! empty ()) + { + iterator p = begin (); + delete *p; + erase (p); + } +} + +void +tree_classdef_attribute_list::accept (tree_walker& tw) +{ + tw.visit_classdef_attribute_list (*this); +} + +// Classdef superclass + +void +tree_classdef_superclass::accept (tree_walker& tw) +{ + tw.visit_classdef_superclass (*this); +} + +// Classdef superclass_list + +tree_classdef_superclass_list::~tree_classdef_superclass_list (void) +{ + while (! empty ()) + { + iterator p = begin (); + delete *p; + erase (p); + } +} + +void +tree_classdef_superclass_list::accept (tree_walker& tw) +{ + tw.visit_classdef_superclass_list (*this); +} + +// Classdef property + +void +tree_classdef_property::accept (tree_walker& tw) +{ + tw.visit_classdef_property (*this); +} + +// Classdef property_list + +tree_classdef_property_list::~tree_classdef_property_list (void) +{ + while (! empty ()) + { + iterator p = begin (); + delete *p; + erase (p); + } +} + +void +tree_classdef_property_list::accept (tree_walker& tw) +{ + tw.visit_classdef_property_list (*this); +} + +// Classdef properties_block + +void +tree_classdef_properties_block::accept (tree_walker& tw) +{ + tw.visit_classdef_properties_block (*this); +} + +// Classdef methods_list + +void +tree_classdef_methods_list::accept (tree_walker& tw) +{ + tw.visit_classdef_methods_list (*this); +} + +// Classdef methods_block + +void +tree_classdef_methods_block::accept (tree_walker& tw) +{ + tw.visit_classdef_methods_block (*this); +} + +// Classdef event + +void +tree_classdef_event::accept (tree_walker& tw) +{ + tw.visit_classdef_event (*this); +} + +// Classdef events_list + +tree_classdef_events_list::~tree_classdef_events_list (void) +{ + while (! empty ()) + { + iterator p = begin (); + delete *p; + erase (p); + } +} + +void +tree_classdef_events_list::accept (tree_walker& tw) +{ + tw.visit_classdef_events_list (*this); +} + +// Classdef events_block + +void +tree_classdef_events_block::accept (tree_walker& tw) +{ + tw.visit_classdef_events_block (*this); +} + +// Classdef enum + +void +tree_classdef_enum::accept (tree_walker& tw) +{ + tw.visit_classdef_enum (*this); +} + +// Classdef enum_list + +tree_classdef_enum_list::~tree_classdef_enum_list (void) +{ + while (! empty ()) + { + iterator p = begin (); + delete *p; + erase (p); + } +} + +void +tree_classdef_enum_list::accept (tree_walker& tw) +{ + tw.visit_classdef_enum_list (*this); +} + +// Classdef enum_block + +void +tree_classdef_enum_block::accept (tree_walker& tw) +{ + tw.visit_classdef_enum_block (*this); +} + +// Classdef body + +tree_classdef_body::~tree_classdef_body (void) +{ + while (! properties_lst.empty ()) + { + properties_list_iterator p = properties_lst.begin (); + delete *p; + properties_lst.erase (p); + } + + while (! methods_lst.empty ()) + { + methods_list_iterator p = methods_lst.begin (); + delete *p; + methods_lst.erase (p); + } + + while (! events_lst.empty ()) + { + events_list_iterator p = events_lst.begin (); + delete *p; + events_lst.erase (p); + } + + while (! enum_lst.empty ()) + { + enum_list_iterator p = enum_lst.begin (); + delete *p; + enum_lst.erase (p); + } +} + +// Classdef + +octave_function* +tree_classdef::make_meta_class (void) +{ + octave_value retval; + cdef_class cls = cdef_class::make_meta_class (this); + + if (cls.ok ()) + return cls.get_constructor_function (); + + return 0; +} + +tree_classdef * +tree_classdef::dup (symbol_table::scope_id, + symbol_table::context_id) const +{ + // FIXME + return 0; +} + +void +tree_classdef::accept (tree_walker& tw) +{ + tw.visit_classdef (*this); +} diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/pt-classdef.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/parse-tree/pt-classdef.h Thu Dec 05 12:04:40 2013 -0500 @@ -0,0 +1,660 @@ +/* + +Copyright (C) 2012-2013 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_tree_classdef_h) +#define octave_tree_classdef_h 1 + +class octave_value; + +class tree_walker; + +#include "pt-cmd.h" +#include "pt-exp.h" +#include "pt-id.h" + +#include "base-list.h" + +#include + +class tree_classdef_attribute +{ +public: + + tree_classdef_attribute (tree_identifier *i = 0, tree_expression *e = 0) + : id (i), expr (e), neg (false) { } + + tree_classdef_attribute (tree_identifier *i, bool b) + : id (i), expr (0), neg (b) { } + + ~tree_classdef_attribute (void) + { + delete id; + delete expr; + } + + tree_identifier *ident (void) { return id; } + + tree_expression *expression (void) { return expr; } + + bool negate (void) { return neg; } + + void accept (tree_walker&); + +private: + + tree_identifier *id; + tree_expression *expr; + bool neg; + + // No copying! + + tree_classdef_attribute (const tree_classdef_attribute&); + + tree_classdef_attribute& operator = (const tree_classdef_attribute&); +}; + +class tree_classdef_attribute_list : public octave_base_list +{ +public: + + tree_classdef_attribute_list (void) { } + + tree_classdef_attribute_list (tree_classdef_attribute *a) { append (a); } + + tree_classdef_attribute_list (const octave_base_list& a) + : octave_base_list (a) { } + + ~tree_classdef_attribute_list (void); + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_attribute_list (const tree_classdef_attribute_list&); + + tree_classdef_attribute_list& operator = (const tree_classdef_attribute_list&); +}; + +class tree_classdef_superclass +{ +public: + + tree_classdef_superclass (tree_identifier *i = 0, tree_identifier *p = 0) + : id (i), pkg (p) { } + + ~tree_classdef_superclass (void) + { + delete id; + delete pkg; + } + + tree_identifier *ident (void) { return id; } + + tree_identifier * package (void) { return pkg; } + + void accept (tree_walker&); + +private: + + tree_identifier *id; + tree_identifier *pkg; + + // No copying! + + tree_classdef_superclass (const tree_classdef_superclass&); + + tree_classdef_superclass& operator = (const tree_classdef_superclass&); +}; + +class tree_classdef_superclass_list : public octave_base_list +{ +public: + + tree_classdef_superclass_list (void) { } + + tree_classdef_superclass_list (tree_classdef_superclass *sc) { append (sc); } + + tree_classdef_superclass_list (const octave_base_list& a) + : octave_base_list (a) { } + + ~tree_classdef_superclass_list (void); + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_superclass_list (const tree_classdef_superclass_list&); + + tree_classdef_superclass_list& operator = (const tree_classdef_superclass_list&); +}; + +template +class tree_classdef_element : public tree +{ +public: + + tree_classdef_element (tree_classdef_attribute_list *a, + octave_base_list *elist, + octave_comment_list *lc, octave_comment_list *tc, + int l = -1, int c = -1) + : tree (l, c), attr_list (a), elt_list (elist), + lead_comm (lc), trail_comm (tc) + { } + + ~tree_classdef_element (void) + { + delete attr_list; + delete elt_list; + delete lead_comm; + delete trail_comm; + } + + tree_classdef_attribute_list *attribute_list (void) { return attr_list; } + + octave_base_list *element_list (void) { return elt_list; } + + octave_comment_list *leading_comment (void) { return lead_comm; } + + octave_comment_list *trailing_comment (void) { return trail_comm; } + + void accept (tree_walker&) { } + +private: + + // List of attributes that apply to this class. + tree_classdef_attribute_list *attr_list; + + // The list of objects contained in this block. + octave_base_list *elt_list; + + // Comment preceding the token marking the beginning of the block. + octave_comment_list *lead_comm; + + // Comment preceding END token. + octave_comment_list *trail_comm; + + // No copying! + + tree_classdef_element (const tree_classdef_element&); + + tree_classdef_element& operator = (const tree_classdef_element&); +}; + +class tree_classdef_property +{ +public: + + tree_classdef_property (tree_identifier *i = 0, tree_expression *e = 0) + : id (i), expr (e) { } + + ~tree_classdef_property (void) + { + delete id; + delete expr; + } + + tree_identifier *ident (void) { return id; } + + tree_expression *expression (void) { return expr; } + + void accept (tree_walker&); + +private: + + tree_identifier *id; + tree_expression *expr; + + // No copying! + + tree_classdef_property (const tree_classdef_property&); + + tree_classdef_property& operator = (const tree_classdef_property&); +}; + +class tree_classdef_property_list : public octave_base_list +{ +public: + + tree_classdef_property_list (void) { } + + tree_classdef_property_list (tree_classdef_property* p) { append (p); } + + tree_classdef_property_list (const octave_base_list& a) + : octave_base_list (a) { } + + ~tree_classdef_property_list (void); + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_property_list (const tree_classdef_property_list&); + + tree_classdef_property_list& operator = (const tree_classdef_property_list&); +}; + +class tree_classdef_properties_block + : public tree_classdef_element +{ +public: + + tree_classdef_properties_block (tree_classdef_attribute_list *a, + tree_classdef_property_list *plist, + octave_comment_list *lc, + octave_comment_list *tc, + int l = -1, int c = -1) + : tree_classdef_element (a, plist, lc, tc, l, c) { } + + ~tree_classdef_properties_block (void) { } + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_properties_block (const tree_classdef_properties_block&); + + tree_classdef_properties_block& operator = (const tree_classdef_properties_block&); +}; + +class tree_classdef_methods_list : public octave_base_list +{ +public: + + tree_classdef_methods_list (void) { } + + tree_classdef_methods_list (const octave_value& f) { append (f); } + + tree_classdef_methods_list (const octave_base_list& a) + : octave_base_list (a) { } + + ~tree_classdef_methods_list (void) { } + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_methods_list (const tree_classdef_methods_list&); + + tree_classdef_methods_list& operator = (const tree_classdef_methods_list&); +}; + +class tree_classdef_methods_block : public tree_classdef_element +{ +public: + + tree_classdef_methods_block (tree_classdef_attribute_list *a, + tree_classdef_methods_list *mlist, + octave_comment_list *lc, + octave_comment_list *tc, int l = -1, int c = -1) + : tree_classdef_element (a, mlist, lc, tc, l, c) { } + + ~tree_classdef_methods_block (void) { } + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_methods_block (const tree_classdef_methods_block&); + + tree_classdef_methods_block& operator = (const tree_classdef_methods_block&); +}; + +class tree_classdef_event +{ +public: + + tree_classdef_event (tree_identifier *i = 0) : id (i) { } + + ~tree_classdef_event (void) + { + delete id; + } + + tree_identifier *ident (void) { return id; } + + void accept (tree_walker&); + +private: + + tree_identifier *id; + + // No copying! + + tree_classdef_event (const tree_classdef_event&); + + tree_classdef_event& operator = (const tree_classdef_event&); +}; + +class tree_classdef_events_list : public octave_base_list +{ +public: + + tree_classdef_events_list (void) { } + + tree_classdef_events_list (tree_classdef_event *e) { append (e); } + + tree_classdef_events_list (const octave_base_list& a) + : octave_base_list (a) { } + + ~tree_classdef_events_list (void); + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_events_list (const tree_classdef_events_list&); + + tree_classdef_events_list& operator = (const tree_classdef_events_list&); +}; + +class tree_classdef_events_block + : public tree_classdef_element +{ +public: + + tree_classdef_events_block (tree_classdef_attribute_list *a, + tree_classdef_events_list *elist, + octave_comment_list *lc, + octave_comment_list *tc, int l = -1, int c = -1) + : tree_classdef_element (a, elist, lc, tc, l, c) { } + + ~tree_classdef_events_block (void) { } + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_events_block (const tree_classdef_events_block&); + + tree_classdef_events_block& operator = (const tree_classdef_events_block&); +}; + +class tree_classdef_enum +{ +public: + + tree_classdef_enum (void) : id (0), expr (0) { } + + tree_classdef_enum (tree_identifier *i, tree_expression *e) + : id (i), expr (e) { } + + ~tree_classdef_enum (void) + { + delete id; + delete expr; + } + + tree_identifier *ident (void) { return id; } + + tree_expression *expression (void) { return expr; } + + void accept (tree_walker&); + +private: + + tree_identifier *id; + tree_expression *expr; + + // No copying! + + tree_classdef_enum (const tree_classdef_enum&); + + tree_classdef_enum& operator = (const tree_classdef_enum&); +}; + +class tree_classdef_enum_list : public octave_base_list +{ +public: + + tree_classdef_enum_list (void) { } + + tree_classdef_enum_list (tree_classdef_enum *e) { append (e); } + + tree_classdef_enum_list (const octave_base_list& a) + : octave_base_list (a) { } + + ~tree_classdef_enum_list (void); + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_enum_list (const tree_classdef_enum_list&); + + tree_classdef_enum_list& operator = (const tree_classdef_enum_list&); +}; + +class tree_classdef_enum_block + : public tree_classdef_element +{ +public: + + tree_classdef_enum_block (tree_classdef_attribute_list *a, + tree_classdef_enum_list *elist, + octave_comment_list *lc, + octave_comment_list *tc, int l = -1, int c = -1) + : tree_classdef_element (a, elist, lc, tc, l, c) { } + + ~tree_classdef_enum_block (void) { } + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_enum_block (const tree_classdef_enum_block&); + + tree_classdef_enum_block& operator = (const tree_classdef_enum_block&); +}; + +class tree_classdef_body +{ +public: + + typedef std::list::iterator properties_list_iterator; + typedef std::list::const_iterator properties_list_const_iterator; + + typedef std::list::iterator methods_list_iterator; + typedef std::list::const_iterator methods_list_const_iterator; + + typedef std::list::iterator events_list_iterator; + typedef std::list::const_iterator events_list_const_iterator; + + typedef std::list::iterator enum_list_iterator; + typedef std::list::const_iterator enum_list_const_iterator; + + tree_classdef_body (void) + : properties_lst (), methods_lst (), events_lst (), enum_lst () { } + + tree_classdef_body (tree_classdef_properties_block *pb) + : properties_lst (), methods_lst (), events_lst (), enum_lst () + { + append (pb); + } + + tree_classdef_body (tree_classdef_methods_block *mb) + : properties_lst (), methods_lst (), events_lst (), enum_lst () + { + append (mb); + } + + tree_classdef_body (tree_classdef_events_block *evb) + : properties_lst (), methods_lst (), events_lst (), enum_lst () + { + append (evb); + } + + tree_classdef_body (tree_classdef_enum_block *enb) + : properties_lst (), methods_lst (), events_lst (), enum_lst () + { + append (enb); + } + + ~tree_classdef_body (void); + + void append (tree_classdef_properties_block *pb) + { + properties_lst.push_back (pb); + } + + void append (tree_classdef_methods_block *mb) + { + methods_lst.push_back (mb); + } + + void append (tree_classdef_events_block *evb) + { + events_lst.push_back (evb); + } + + void append (tree_classdef_enum_block *enb) + { + enum_lst.push_back (enb); + } + + std::list properties_list (void) + { + return properties_lst; + } + + std::list methods_list (void) + { + return methods_lst; + } + + std::list events_list (void) + { + return events_lst; + } + + std::list enum_list (void) + { + return enum_lst; + } + + void accept (tree_walker&); + +private: + + std::list properties_lst; + + std::list methods_lst; + + std::list events_lst; + + std::list enum_lst; + + // No copying! + + tree_classdef_body (const tree_classdef_body&); + + tree_classdef_body& operator = (const tree_classdef_body&); +}; + +// Classdef definition. + +class tree_classdef : public tree_command +{ +public: + + tree_classdef (tree_classdef_attribute_list *a, tree_identifier *i, + tree_classdef_superclass_list *sc, + tree_classdef_body *b, octave_comment_list *lc, + octave_comment_list *tc, + const std::string& pn = std::string (), int l = -1, + int c = -1) + : tree_command (l, c), attr_list (a), id (i), + supclass_list (sc), element_list (b), lead_comm (lc), trail_comm (tc), + pack_name (pn) { } + + ~tree_classdef (void) + { + delete attr_list; + delete id; + delete supclass_list; + delete element_list; + delete lead_comm; + delete trail_comm; + } + + tree_classdef_attribute_list *attribute_list (void) { return attr_list; } + + tree_identifier *ident (void) { return id; } + + tree_classdef_superclass_list *superclass_list (void) { return supclass_list; } + + tree_classdef_body *body (void) { return element_list; } + + octave_comment_list *leading_comment (void) { return lead_comm; } + octave_comment_list *trailing_comment (void) { return trail_comm; } + + const std::string& package_name (void) const { return pack_name; } + + octave_function* make_meta_class (void); + + tree_classdef *dup (symbol_table::scope_id scope, + symbol_table::context_id context) const; + + void accept (tree_walker& tw); + +private: + + tree_classdef_attribute_list *attr_list; + + tree_identifier *id; + + tree_classdef_superclass_list *supclass_list; + + tree_classdef_body *element_list; + + octave_comment_list *lead_comm; + octave_comment_list *trail_comm; + + std::string pack_name; + + // No copying! + + tree_classdef (const tree_classdef&); + + tree_classdef& operator = (const tree_classdef&); +}; + +#endif diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/pt-eval.cc --- a/libinterp/parse-tree/pt-eval.cc Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/parse-tree/pt-eval.cc Thu Dec 05 12:04:40 2013 -0500 @@ -637,6 +637,12 @@ } void +tree_evaluator::visit_funcall (tree_funcall&) +{ + panic_impossible (); +} + +void tree_evaluator::visit_parameter_list (tree_parameter_list&) { panic_impossible (); diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/pt-eval.h --- a/libinterp/parse-tree/pt-eval.h Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/parse-tree/pt-eval.h Thu Dec 05 12:04:40 2013 -0500 @@ -102,6 +102,8 @@ void visit_fcn_handle (tree_fcn_handle&); + void visit_funcall (tree_funcall&); + void visit_parameter_list (tree_parameter_list&); void visit_postfix_expression (tree_postfix_expression&); diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/pt-exp.h --- a/libinterp/parse-tree/pt-exp.h Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/parse-tree/pt-exp.h Thu Dec 05 12:04:40 2013 -0500 @@ -40,7 +40,7 @@ public: tree_expression (int l = -1, int c = -1) - : tree (l, c), num_parens (0), postfix_indexed (false), + : tree (l, c), num_parens (0), postfix_index_type ('\0'), print_flag (false) { } virtual ~tree_expression (void) { } @@ -87,7 +87,9 @@ int paren_count (void) const { return num_parens; } - bool is_postfix_indexed (void) const { return postfix_indexed; } + bool is_postfix_indexed (void) const { return (postfix_index_type != '\0'); } + + char postfix_index (void) const { return postfix_index_type; } // Check if the result of the expression should be printed. // Should normally be used in conjunction with @@ -108,9 +110,9 @@ return this; } - tree_expression *mark_postfix_indexed (void) + tree_expression *set_postfix_index (char type) { - postfix_indexed = true; + postfix_index_type = type; return this; } @@ -123,7 +125,7 @@ virtual void copy_base (const tree_expression& e) { num_parens = e.num_parens; - postfix_indexed = e.postfix_indexed; + postfix_index_type = e.postfix_index_type; print_flag = e.print_flag; } @@ -137,9 +139,10 @@ // ==> 0 for expression e2 int num_parens; - // A flag that says whether this expression has an index associated - // with it. See the code in tree_identifier::rvalue for the rationale. - bool postfix_indexed; + // The first index type associated with this expression. This field + // is 0 (character '\0') if the expression has no associated index. + // See the code in tree_identifier::rvalue for the rationale. + char postfix_index_type; // Print result of rvalue for this expression? bool print_flag; diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/pt-funcall.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/parse-tree/pt-funcall.cc Thu Dec 05 12:04:40 2013 -0500 @@ -0,0 +1,83 @@ +/* + +Copyright (C) 2012-2013 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "ov-fcn.h" +#include "pt-funcall.h" +#include "pt-walk.h" + +// Function call objects. + +void +tree_funcall::print (std::ostream& os, bool pr_as_read_syntax, + bool pr_orig_text) +{ + print_raw (os, pr_as_read_syntax, pr_orig_text); +} + +void +tree_funcall::print_raw (std::ostream& os, bool pr_as_read_syntax, + bool pr_orig_text) +{ + if (pr_orig_text) + { + os << original_text (); + } + else + { + octave_function *fp = fcn.function_value (); + std::string nm = fp ? fp->name () : std::string (""); + + os << nm << " ("; + + octave_idx_type len = args.length (); + for (octave_idx_type i = 0; i < len; i++) + { + args(i).print_raw (os, pr_as_read_syntax); + + if (i < len - 1) + os << ", "; + } + + os << ")"; + } +} + +tree_funcall * +tree_funcall::dup (symbol_table::scope_id, + symbol_table::context_id context) const +{ + tree_funcall *new_fc = new tree_funcall (fcn, args, line (), column ()); + + new_fc->copy_base (*new_fc); + + return new_fc; +} + +void +tree_funcall::accept (tree_walker& tw) +{ + tw.visit_funcall (*this); +} diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/pt-funcall.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/parse-tree/pt-funcall.h Thu Dec 05 12:04:40 2013 -0500 @@ -0,0 +1,101 @@ +/* + +Copyright (C) 2012-2013 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_tree_funcall_h) +#define octave_tree_funcall_h 1 + +#include "ov.h" +#include "oct-obj.h" +#include "parse.h" +#include "pt-exp.h" + +// Function call. This class only represents function calls that have +// known functions (most useful for calls to built-in functions that +// are generated by the parser) and fixed argument lists, known at +// compile time. + +class +tree_funcall : public tree_expression +{ +public: + + tree_funcall (const octave_value& f, const octave_value_list& a, + int l = -1, int c = -1) + : tree_expression (l, c), fcn (f), args (a) + { + if (! fcn.is_function ()) + error ("tree_funcall: invalid function"); + } + + ~tree_funcall (void) { } + + bool has_magic_end (void) const { return false; } + + void print (std::ostream& os, bool pr_as_read_syntax = false, + bool pr_orig_txt = true); + + void print_raw (std::ostream& os, bool pr_as_read_syntax = false, + bool pr_orig_txt = true); + + tree_funcall *dup (symbol_table::scope_id, + symbol_table::context_id context) const; + + octave_value rvalue1 (int nargout) + { + octave_value retval; + + const octave_value_list tmp = rvalue (nargout); + + if (! tmp.empty ()) + retval = tmp(0); + + return retval; + } + + octave_value_list rvalue (int nargout) + { + return feval (fcn.function_value (), args, nargout); + } + + octave_value function (void) const { return fcn; } + + octave_value_list arguments (void) const { return args; } + + void accept (tree_walker& tw); + +private: + + // Function to call. Error if not a valid function at time of + // construction. + octave_value fcn; + + // Argument list. + octave_value_list args; + + // No copying! + + tree_funcall (const tree_funcall&); + + tree_funcall& operator = (const tree_funcall&); +}; + +#endif diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/pt-id.cc --- a/libinterp/parse-tree/pt-id.cc Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/parse-tree/pt-id.cc Thu Dec 05 12:04:40 2013 -0500 @@ -76,13 +76,19 @@ // // If this identifier refers to a function, we need to know // whether it is indexed so that we can do the same thing - // for 'f' and 'f()'. If the index is present, return the - // function object and let tree_index_expression::rvalue - // handle indexing. Otherwise, arrange to call the function - // here, so that we don't return the function definition as - // a value. + // for 'f' and 'f()'. If the index is present and the function + // object declares it can handle it, return the function object + // and let tree_index_expression::rvalue handle indexing. + // Otherwise, arrange to call the function here, so that we don't + // return the function definition as a value. - if (val.is_function () && ! is_postfix_indexed ()) + octave_function *fcn = 0; + + if (val.is_function ()) + fcn = val.function_value (true); + + if (fcn && ! (is_postfix_indexed () + && fcn->is_postfix_index_handled (postfix_index ()))) { octave_value_list tmp_args; diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/pt-id.h --- a/libinterp/parse-tree/pt-id.h Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/parse-tree/pt-id.h Thu Dec 05 12:04:40 2013 -0500 @@ -32,6 +32,7 @@ class tree_walker; +#include "oct-lvalue.h" #include "pt-bp.h" #include "pt-exp.h" #include "symtab.h" diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/pt-pr-code.cc --- a/libinterp/parse-tree/pt-pr-code.cc Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/parse-tree/pt-pr-code.cc Thu Dec 05 12:04:40 2013 -0500 @@ -749,6 +749,18 @@ } void +tree_print_code::visit_funcall (tree_funcall& fc) +{ + indent (); + + print_parens (fc, "("); + + fc.print_raw (os, true, print_original_text); + + print_parens (fc, ")"); +} + +void tree_print_code::visit_parameter_list (tree_parameter_list& lst) { tree_parameter_list::iterator p = lst.begin (); diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/pt-pr-code.h --- a/libinterp/parse-tree/pt-pr-code.h Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/parse-tree/pt-pr-code.h Thu Dec 05 12:04:40 2013 -0500 @@ -109,6 +109,8 @@ void visit_fcn_handle (tree_fcn_handle&); + void visit_funcall (tree_funcall&); + void visit_parameter_list (tree_parameter_list&); void visit_postfix_expression (tree_postfix_expression&); diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/pt-walk.h --- a/libinterp/parse-tree/pt-walk.h Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/parse-tree/pt-walk.h Thu Dec 05 12:04:40 2013 -0500 @@ -52,6 +52,7 @@ class tree_no_op_command; class tree_constant; class tree_fcn_handle; +class tree_funcall; class tree_parameter_list; class tree_postfix_expression; class tree_prefix_expression; @@ -65,6 +66,24 @@ class tree_while_command; class tree_do_until_command; +class tree_classdef_attribute; +class tree_classdef_attribute_list; +class tree_classdef_superclass; +class tree_classdef_superclass_list; +class tree_classdef_property; +class tree_classdef_property_list; +class tree_classdef_properties_block; +class tree_classdef_methods_list; +class tree_classdef_methods_block; +class tree_classdef_event; +class tree_classdef_events_list; +class tree_classdef_events_block; +class tree_classdef_enum; +class tree_classdef_enum_list; +class tree_classdef_enum_block; +class tree_classdef_body; +class tree_classdef; + class tree_walker { @@ -158,6 +177,9 @@ visit_fcn_handle (tree_fcn_handle&) = 0; virtual void + visit_funcall (tree_funcall&) = 0; + + virtual void visit_parameter_list (tree_parameter_list&) = 0; virtual void @@ -193,6 +215,57 @@ virtual void visit_do_until_command (tree_do_until_command&) = 0; + virtual void + visit_classdef_attribute (tree_classdef_attribute&) { } /* = 0; */ + + virtual void + visit_classdef_attribute_list (tree_classdef_attribute_list&) { } /* = 0; */ + + virtual void + visit_classdef_superclass (tree_classdef_superclass&) { } /* = 0; */ + + virtual void + visit_classdef_superclass_list (tree_classdef_superclass_list&) { } /* = 0; */ + + virtual void + visit_classdef_property (tree_classdef_property&) { } /* = 0; */ + + virtual void + visit_classdef_property_list (tree_classdef_property_list&) { } /* = 0; */ + + virtual void + visit_classdef_properties_block (tree_classdef_properties_block&) { } /* = 0; */ + + virtual void + visit_classdef_methods_list (tree_classdef_methods_list&) { } /* = 0; */ + + virtual void + visit_classdef_methods_block (tree_classdef_methods_block&) { } /* = 0; */ + + virtual void + visit_classdef_event (tree_classdef_event&) { } /* = 0; */ + + virtual void + visit_classdef_events_list (tree_classdef_events_list&) { } /* = 0; */ + + virtual void + visit_classdef_events_block (tree_classdef_events_block&) { } /* = 0; */ + + virtual void + visit_classdef_enum (tree_classdef_enum&) { } /* = 0; */ + + virtual void + visit_classdef_enum_list (tree_classdef_enum_list&) { } /* = 0; */ + + virtual void + visit_classdef_enum_block (tree_classdef_enum_block&) { } /* = 0; */ + + virtual void + visit_classdef_body (tree_classdef_body&) { } /* = 0; */ + + virtual void + visit_classdef (tree_classdef&) { } /* = 0; */ + protected: tree_walker (void) { } diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/token.cc --- a/libinterp/parse-tree/token.cc Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/parse-tree/token.cc Thu Dec 05 12:04:40 2013 -0500 @@ -97,38 +97,50 @@ sr = s; } -token::token (int tv, symbol_table::symbol_record *cls, - symbol_table::symbol_record *pkg, int l, int c) +token::token (int tv, const std::string& pkg, const std::string& cls, + int l, int c) +{ + maybe_cmd = false; + tspc = false; + line_num = l; + column_num = c; + tok_val = tv; + type_tag = meta_name_token; + mc.package_nm = new std::string (pkg); + mc.class_nm = new std::string (cls); +} + +token::token (int tv, const std::string& mth, const std::string& pkg, + const std::string& cls, int l, int c) { maybe_cmd = false; tspc = false; line_num = l; column_num = c; tok_val = tv; - type_tag = meta_rec_token; - mc.cr = cls; - mc.pr = pkg; -} - -token::token (int tv, symbol_table::symbol_record *mth, - symbol_table::symbol_record *cls, - symbol_table::symbol_record *pkg, int l, int c) -{ - maybe_cmd = false; - tspc = false; - line_num = l; - column_num = c; - tok_val = tv; - type_tag = scls_rec_token; - sc.mr = mth; - sc.cr = cls; - sc.pr = pkg; + type_tag = scls_name_token; + sc.method_nm = new std::string (mth); + sc.package_nm = new std::string (pkg); + sc.class_nm = new std::string (cls); } token::~token (void) { if (type_tag == string_token) delete str; + + if (type_tag == scls_name_token) + { + delete sc.method_nm; + delete sc.package_nm; + delete sc.class_nm; + } + + if (type_tag == meta_name_token) + { + delete mc.package_nm; + delete mc.class_nm; + } } std::string @@ -172,39 +184,39 @@ return sr; } -symbol_table::symbol_record * -token::method_rec (void) +std::string +token::superclass_method_name (void) { - assert (type_tag == scls_rec_token); - return sc.mr; + assert (type_tag == scls_name_token); + return *sc.method_nm; } -symbol_table::symbol_record * -token::class_rec (void) +std::string +token::superclass_package_name (void) { - assert (type_tag == scls_rec_token); - return sc.cr; + assert (type_tag == scls_name_token); + return *sc.package_nm; } -symbol_table::symbol_record * -token::package_rec (void) +std::string +token::superclass_class_name (void) { - assert (type_tag == scls_rec_token); - return sc.pr; + assert (type_tag == scls_name_token); + return *sc.class_nm; } -symbol_table::symbol_record * -token::meta_class_rec (void) +std::string +token::meta_package_name (void) { - assert (type_tag == meta_rec_token); - return mc.cr; + assert (type_tag == meta_name_token); + return *mc.package_nm; } -symbol_table::symbol_record * -token::meta_package_rec (void) +std::string +token::meta_class_name (void) { - assert (type_tag == meta_rec_token); - return mc.pr; + assert (type_tag == meta_name_token); + return *mc.class_nm; } std::string diff -r 8cf2b8617e85 -r 69ac19bb878e libinterp/parse-tree/token.h --- a/libinterp/parse-tree/token.h Thu Dec 05 10:48:21 2013 -0500 +++ b/libinterp/parse-tree/token.h Thu Dec 05 12:04:40 2013 -0500 @@ -40,8 +40,8 @@ double_token, ettype_token, sym_rec_token, - scls_rec_token, - meta_rec_token + scls_name_token, + meta_name_token }; enum end_tok_type @@ -69,11 +69,10 @@ int l = -1, int c = -1); token (int tv, end_tok_type t, int l = -1, int c = -1); token (int tv, symbol_table::symbol_record *s, int l = -1, int c = -1); - token (int tv, symbol_table::symbol_record *cls, - symbol_table::symbol_record *pkg, int l = -1, int c = -1); - token (int tv, symbol_table::symbol_record *mth, - symbol_table::symbol_record *cls, - symbol_table::symbol_record *pkg, int l = -1, int c = -1); + token (int tv, const std::string& pkg, const std::string& cls, + int l = -1, int c = -1); + token (int tv, const std::string& mth, const std::string& pkg, + const std::string& cls, int l = -1, int c = -1); ~token (void); @@ -106,12 +105,12 @@ end_tok_type ettype (void) const; symbol_table::symbol_record *sym_rec (void); - symbol_table::symbol_record *method_rec (void); - symbol_table::symbol_record *class_rec (void); - symbol_table::symbol_record *package_rec (void); + std::string superclass_method_name (void); + std::string superclass_package_name (void); + std::string superclass_class_name (void); - symbol_table::symbol_record *meta_class_rec (void); - symbol_table::symbol_record *meta_package_rec (void); + std::string meta_package_name (void); + std::string meta_class_name (void); std::string text_rep (void); @@ -137,14 +136,14 @@ symbol_table::symbol_record *sr; struct { - symbol_table::symbol_record *mr; - symbol_table::symbol_record *cr; - symbol_table::symbol_record *pr; + std::string *method_nm; + std::string *package_nm; + std::string *class_nm; } sc; struct { - symbol_table::symbol_record *cr; - symbol_table::symbol_record *pr; + std::string *package_nm; + std::string *class_nm; } mc; }; std::string orig_text; diff -r 8cf2b8617e85 -r 69ac19bb878e liboctave/util/base-list.h --- a/liboctave/util/base-list.h Thu Dec 05 10:48:21 2013 -0500 +++ b/liboctave/util/base-list.h Thu Dec 05 12:04:40 2013 -0500 @@ -104,8 +104,6 @@ // For backward compatibility. void append (const elt_type& s) { lst.push_back (s); } -protected: - octave_base_list (void) : lst () { } octave_base_list (const std::list& l) : lst (l) { } diff -r 8cf2b8617e85 -r 69ac19bb878e scripts/general/bincoeff.m diff -r 8cf2b8617e85 -r 69ac19bb878e scripts/gui/errordlg.m diff -r 8cf2b8617e85 -r 69ac19bb878e scripts/gui/helpdlg.m diff -r 8cf2b8617e85 -r 69ac19bb878e scripts/gui/inputdlg.m diff -r 8cf2b8617e85 -r 69ac19bb878e scripts/gui/listdlg.m diff -r 8cf2b8617e85 -r 69ac19bb878e scripts/gui/msgbox.m diff -r 8cf2b8617e85 -r 69ac19bb878e scripts/gui/private/message_dialog.m diff -r 8cf2b8617e85 -r 69ac19bb878e scripts/gui/questdlg.m diff -r 8cf2b8617e85 -r 69ac19bb878e scripts/gui/warndlg.m diff -r 8cf2b8617e85 -r 69ac19bb878e scripts/miscellaneous/colon.m diff -r 8cf2b8617e85 -r 69ac19bb878e scripts/miscellaneous/genvarname.m diff -r 8cf2b8617e85 -r 69ac19bb878e scripts/plot/appearance/datetick.m diff -r 8cf2b8617e85 -r 69ac19bb878e src/Makefile.am diff -r 8cf2b8617e85 -r 69ac19bb878e test/Makefile.am --- a/test/Makefile.am Thu Dec 05 10:48:21 2013 -0500 +++ b/test/Makefile.am Thu Dec 05 12:04:40 2013 -0500 @@ -56,6 +56,7 @@ include bug-36025/module.mk include bug-38236/module.mk include bug-38691/module.mk +include classdef/module.mk include classes/module.mk include class-concat/module.mk include ctor-vs-method/module.mk diff -r 8cf2b8617e85 -r 69ac19bb878e test/classdef/classdef.tst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/classdef/classdef.tst Thu Dec 05 12:04:40 2013 -0500 @@ -0,0 +1,73 @@ +## Copyright (C) 2013 Ben Abbott +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or (at +## your option) any later version. +## +## Octave is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## . + +%% Test script for classdef OOP. +%% Requires the path to contain the test classes. +%% +%% Note: This script and all classes are also intended to run +%% in MATLAB to test compatibility. Don't break that! +%% +%% To Do: This script tests to ensure that things done correctly work +%% corrrectly. It should also check that things done incorrectly +%% error properly. +%% +%% The classes used for the tests reside in the test/classdef with others +%% in the test directory. +%% +%% The classes provide the ability to test most of the major features +%% of the classdef OOP facilities. There are a number of classes, mostly +%% kind of the same, that create a hierarchy. + +%% Basic classdef tests for value class +%!shared p, q, i, amt +%! q = foo_value_class (); +%! p = foo_value_class (4, 4*12, 50e3); +%! i = p.rate / (12 * 100); +%! amt = (p.principle * i) / (1 - (1 + i)^(-p.term)); +%!assert (isempty (q.rate)); +%!assert (isempty (q.principle)); +%!assert (isempty (q.term)); +%!assert (class (p), "foo_value_class"); +%!assert (p.term, 48); +%!assert (p.rate, 4.0); +%!assert (p.principle, 50e3); +%!assert (p.amount, amt, eps ()) +%!assert (amount (p), amt, eps ()) +%!xtest +%! assert (properties (p), {'rate'; 'term'; 'principle'}) +%!xtest +%! assert (methods (p), {'amount'; 'foo_value_class'}) +%!assert (isempty (foo_value_class().rate)) +%!error foo_value_class.rate + +%% Static method and Constant Property +%!assert (foo_static_method_constant_property.radians_per_cycle, 2*pi); +%!assert (foo_static_method_constant_property().radians_per_cycle, 2*pi); +%!assert (foo_static_method_constant_property().pie, pi); +%!error foo_static_method_constant_property.frequency +%!error foo_static_method_constant_property.cosine +%!test +%! obj = foo_static_method_constant_property; +%! obj.frequency = 10; +%! assert (obj.cosine (0.1), cos (2 * pi * 10 * 0.1), eps ()) +%! assert (obj.sine (0.1), sin (2 * pi * 10 * 0.1), eps ()) + +%!test +%! obj = foo_method_changes_property_size (3); +%! obj = obj.move_element_to_end (2); +%! assert (obj.element, [1 3 2]) diff -r 8cf2b8617e85 -r 69ac19bb878e test/classdef/foo_method_changes_property_size.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/classdef/foo_method_changes_property_size.m Thu Dec 05 12:04:40 2013 -0500 @@ -0,0 +1,14 @@ +classdef foo_method_changes_property_size + properties + element; + end + methods + function obj = foo_method_changes_property_size (n) + obj.element = 1:n; + end + function obj = move_element_to_end (obj, n) + obj.element(end+1) = obj.element(n); + obj.element(n) = []; + end + end +end diff -r 8cf2b8617e85 -r 69ac19bb878e test/classdef/foo_static_method_constant_property.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/classdef/foo_static_method_constant_property.m Thu Dec 05 12:04:40 2013 -0500 @@ -0,0 +1,30 @@ +classdef foo_static_method_constant_property + properties + frequency; + end + properties (Constant = true) + pie = pi; + end + methods + function obj = foo_static_method_constant_property (f) + if (nargin == 1) + obj.frequency = f; + elseif (nargin ~= 0) + error ('foo_static_method_constant_property:SyntaxError', ... + 'foo_static_method_constant_property: Invalid syntax') + end + end + function res = cosine (obj, t) + res = cos (obj.radians_per_cycle () * obj.frequency * t); + end + function res = sine (obj, t) + res = sin (obj.radians_per_cycle () * obj.frequency * t); + end + end + methods (Static) + function res = radians_per_cycle () + res = 2 * foo_static_method_constant_property.pie; + end + end +end + diff -r 8cf2b8617e85 -r 69ac19bb878e test/classdef/foo_value_class.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/classdef/foo_value_class.m Thu Dec 05 12:04:40 2013 -0500 @@ -0,0 +1,28 @@ +classdef foo_value_class + properties + rate; + term; + principle; + end + methods + function obj = foo_value_class (r, t, p) + if (nargin == 3) + obj.rate = r; + obj.term = t; + obj.principle = p; + elseif (nargin ~= 0) + error ('foo_value_class:SyntaxError', ... + 'foo_value_class: Invalid syntax') + end + end + function amt = amount (obj) + i = obj.rate / (12 * 100); + if (i == 0 && obj.term == 0) + amt = obj.principle; + else + amt = (obj.principle * i) / (1 - (1 + i)^(-obj.term)); + end + end + end +end + diff -r 8cf2b8617e85 -r 69ac19bb878e test/classdef/module.mk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/classdef/module.mk Thu Dec 05 12:04:40 2013 -0500 @@ -0,0 +1,7 @@ +classdef_FCN_FILES = \ + classdef/foo_method_changes_property_size.m \ + classdef/foo_static_method_constant_property.m \ + classdef/foo_value_class.m \ + classdef/classdef.tst + +FCN_FILES += $(classdef_FCN_FILES) diff -r 8cf2b8617e85 -r 69ac19bb878e test/classes/classes.tst diff -r 8cf2b8617e85 -r 69ac19bb878e test/classes/module.mk