Mercurial > octave
view libinterp/corefcn/symtab.h @ 23807:336f89b6208b
Use character literals 'c' rather than string literals "c" when possible.
Better performance when string constructor isn't required.
* Figure.cc, __init_qt__.cc, files-dock-widget.cc, file-editor-tab.cc,
file-editor.cc, octave-qscintilla.cc, main-window.cc, octave-dock-widget.cc,
octave-qt-link.cc, parser.cc, webinfo.cc, resource-manager.cc,
settings-dialog.cc, workspace-view.cc, __magick_read__.cc, balance.cc,
debug.cc, dynamic-ld.cc, ft-text-renderer.cc, gl-render.cc, gl2ps-print.cc,
graphics.cc, hook-fcn.h, input.cc, load-path.cc, load-save.cc, ls-hdf5.cc,
oct-hist.cc, oct-stream.cc, pager.cc, pr-output.cc, qz.cc, symtab.cc, symtab.h,
tril.cc, __delaunayn__.cc, __init_fltk__.cc, __voronoi__.cc, audioread.cc,
ccolamd.cc, colamd.cc, convhulln.cc, ov-base-int.cc, ov-base-mat.cc,
ov-base-scalar.cc, ov-base.cc, ov-bool-mat.cc, ov-cell.cc, ov-class.cc,
ov-classdef.cc, ov-colon.cc, ov-complex.cc, ov-cx-mat.cc, ov-fcn-handle.cc,
ov-fcn-inline.cc, ov-fcn.h, ov-flt-cx-mat.cc, ov-flt-re-mat.cc, ov-java.cc,
ov-oncleanup.cc, ov-range.cc, ov-re-mat.cc, ov-re-sparse.cc, ov-str-mat.cc,
ov-struct.cc, ov-usr-fcn.cc, ov.cc, octave.cc, bp-table.cc, jit-ir.cc,
jit-ir.h, jit-typeinfo.cc, pt-funcall.cc, pt-idx.cc, pt-pr-code.cc, pt.h,
Array.cc, CDiagMatrix.cc, CMatrix.cc, CNDArray.cc, CRowVector.cc, CSparse.cc,
Range.cc, boolSparse.cc, dDiagMatrix.cc, dMatrix.cc, dNDArray.cc,
dRowVector.cc, dSparse.cc, fCDiagMatrix.cc, fCMatrix.cc, fCNDArray.cc,
fCRowVector.cc, fDiagMatrix.cc, fMatrix.cc, fNDArray.cc, fRowVector.cc,
idx-vector.cc, intNDArray.cc, CollocWt.cc, DASPK.cc, DASRT.cc, DASSL.cc,
LSODE.cc, oct-time.cc, cmd-hist.cc, kpse.cc, lo-array-errwarn.cc, lo-regexp.cc,
lo-utils.cc, str-vec.cc, url-transfer.cc, main-cli.cc, main-gui.cc,
mkoctfile.in.cc:
Replace 1-character string literals "c" with the character literal 'c'.
author | Rik <rik@octave.org> |
---|---|
date | Fri, 28 Jul 2017 15:40:00 -0700 |
parents | 980f39c3ab90 |
children | 4b0e0cae49db |
line wrap: on
line source
/* Copyright (C) 1993-2017 John W. Eaton Copyright (C) 2009 VZLU Prague 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 <http://www.gnu.org/licenses/>. */ #if ! defined (octave_symtab_h) #define octave_symtab_h 1 #include "octave-config.h" #include <deque> #include <limits> #include <list> #include <map> #include <set> #include <string> #include "glob-match.h" #include "lo-regexp.h" #include "oct-refcount.h" class tree_argument_list; class octave_user_function; #include "ov.h" #include "ovl.h" #include "workspace-element.h" namespace octave { class OCTINTERP_API symbol_table { public: static octave_value dummy_octave_value; typedef size_t context_id; class scope; class fcn_info; class symbol_record { public: // generic variable static const unsigned int local = 1; // varargin, argn, .nargin., .nargout. // (FIXME: is this really used now?) static const unsigned int automatic = 2; // formal parameter static const unsigned int formal = 4; // not listed or cleared (.nargin., .nargout.) static const unsigned int hidden = 8; // inherited from parent scope; not cleared at function exit static const unsigned int inherited = 16; // global (redirects to global scope) static const unsigned int global = 32; // not cleared at function exit static const unsigned int persistent = 64; // this symbol may NOT become a variable. // (symbol added to a static workspace) static const unsigned int added_static = 128; private: class symbol_record_rep { public: symbol_record_rep (scope *s, const std::string& nm, const octave_value& v, unsigned int sc) : m_decl_scope (s), curr_fcn (nullptr), name (nm), value_stack (), storage_class (sc), /* finfo (), */ valid (true), count (1) { value_stack.push_back (v); } // No copying! symbol_record_rep (const symbol_record_rep& ov) = delete; symbol_record_rep& operator = (const symbol_record_rep&) = delete; ~symbol_record_rep (void) = default; void assign (const octave_value& value) { varref () = value; } void assign (octave_value::assign_op op, const std::string& type, const std::list<octave_value_list>& idx, const octave_value& value) { varref().assign (op, type, idx, value); } void assign (octave_value::assign_op op, const octave_value& value) { varref().assign (op, value); } void do_non_const_unary_op (octave_value::unary_op op) { varref().do_non_const_unary_op (op); } void do_non_const_unary_op (octave_value::unary_op op, const std::string& type, const std::list<octave_value_list>& idx) { varref().do_non_const_unary_op (op, type, idx); } octave_value& varref (void) { context_id context = m_decl_scope ? m_decl_scope->current_context () : 0; if (is_global ()) return xglobal_varref (); else if (is_persistent ()) return xpersistent_varref (); else { context_id n = value_stack.size (); while (n++ <= context) value_stack.push_back (octave_value ()); return value_stack[context]; } } octave_value varval (void) const { context_id context = m_decl_scope ? m_decl_scope->current_context () : 0; if (is_global ()) return xglobal_varval (); else if (is_persistent ()) return xpersistent_varval (); else { if (context < value_stack.size ()) return value_stack[context]; else return octave_value (); } } void push_context (scope *sid) { if (! (is_persistent () || is_global ()) && sid == decl_scope ()) value_stack.push_back (octave_value ()); } // If pop_context returns 0, we are out of values and this element // of the symbol table should be deleted. This can happen for // functions like // // function foo (n) // if (n > 0) // foo (n-1); // else // eval ("x = 1"); // endif // endfunction // // Here, X should only exist in the final stack frame. size_t pop_context (scope *sid) { size_t retval = 1; if (! (is_persistent () || is_global ()) && sid == decl_scope ()) { value_stack.pop_back (); retval = value_stack.size (); } return retval; } void clear (void) { clear (decl_scope ()); } void clear (scope *sid); bool is_defined (void) const { return varval ().is_defined (); } bool is_valid (void) const { return valid; } bool is_variable (void) const { return (! is_local () || is_defined ()); } bool is_local (void) const { return storage_class & local; } bool is_automatic (void) const { return storage_class & automatic; } bool is_formal (void) const { return storage_class & formal; } bool is_hidden (void) const { return storage_class & hidden; } bool is_inherited (void) const { return storage_class & inherited; } bool is_global (void) const { return storage_class & global; } bool is_persistent (void) const { return storage_class & persistent; } bool is_added_static (void) const {return storage_class & added_static; } void mark_local (void) { storage_class |= local; } void mark_automatic (void) { storage_class |= automatic; } void mark_formal (void) { storage_class |= formal; } void mark_hidden (void) { storage_class |= hidden; } void mark_inherited (void) { storage_class |= inherited; } void mark_global (void) { if (is_persistent ()) error ("can't make persistent variable %s global", name.c_str ()); storage_class |= global; } void mark_persistent (void) { if (is_global ()) error ("can't make global variable %s persistent", name.c_str ()); storage_class |= persistent; } void mark_added_static (void) { storage_class |= added_static; } void unmark_local (void) { storage_class &= ~local; } void unmark_automatic (void) { storage_class &= ~automatic; } void unmark_formal (void) { storage_class &= ~formal; } void unmark_hidden (void) { storage_class &= ~hidden; } void unmark_inherited (void) { storage_class &= ~inherited; } void unmark_global (void) { storage_class &= ~global; } void unmark_persistent (void) { storage_class &= ~persistent; } void unmark_added_static (void) { storage_class &= ~added_static; } void init_persistent (void); void invalidate (void) { valid = false; } void erase_persistent (void); scope *decl_scope (void) { return m_decl_scope; } void set_curr_fcn (octave_user_function *fcn) { curr_fcn = fcn; } symbol_record_rep * dup (scope *new_scope) const; octave_value dump (void) const; scope *m_decl_scope; octave_user_function *curr_fcn; std::string name; std::deque<octave_value> value_stack; unsigned int storage_class; // fcn_info *finfo; bool valid; refcount<size_t> count; private: octave_value& xglobal_varref (void); octave_value& xpersistent_varref (void); octave_value xglobal_varval (void) const; octave_value xpersistent_varval (void) const; }; public: symbol_record (void); symbol_record (scope *s, const std::string& nm = "", const octave_value& v = octave_value (), unsigned int sc = local) : rep (new symbol_record_rep (s, nm, v, sc)) { } symbol_record (const symbol_record& sr) : rep (sr.rep) { rep->count++; } symbol_record& operator = (const symbol_record& sr) { if (this != &sr) { if (--rep->count == 0) delete rep; rep = sr.rep; rep->count++; } return *this; } ~symbol_record (void) { if (--rep->count == 0) delete rep; } symbol_record dup (scope *sid) const { return symbol_record (rep->dup (sid)); } const std::string& name (void) const { return rep->name; } void rename (const std::string& new_name) { rep->name = new_name; } octave_value find (const octave_value_list& args = octave_value_list ()) const; void assign (const octave_value& value) { rep->assign (value); } void assign (octave_value::assign_op op, const std::string& type, const std::list<octave_value_list>& idx, const octave_value& value) { rep->assign (op, type, idx, value); } void assign (octave_value::assign_op op, const octave_value& value) { rep->assign (op, value); } void do_non_const_unary_op (octave_value::unary_op op) { rep->do_non_const_unary_op (op); } void do_non_const_unary_op (octave_value::unary_op op, const std::string& type, const std::list<octave_value_list>& idx) { rep->do_non_const_unary_op (op, type, idx); } // Delete when deprecated varref functions are removed. octave_value& varref (void) { return rep->varref (); } octave_value varval (void) const { return rep->varval (); } void push_context (scope *sid) { rep->push_context (sid); } size_t pop_context (scope *sid) { return rep->pop_context (sid); } void clear (void) { rep->clear (); } void clear (scope *sid) { rep->clear (sid); } bool is_defined (void) const { return rep->is_defined (); } bool is_undefined (void) const { return ! rep->is_defined (); } bool is_valid (void) const { return rep->is_valid (); } bool is_variable (void) const { return rep->is_variable (); } bool is_local (void) const { return rep->is_local (); } bool is_automatic (void) const { return rep->is_automatic (); } bool is_formal (void) const { return rep->is_formal (); } bool is_global (void) const { return rep->is_global (); } bool is_hidden (void) const { return rep->is_hidden (); } bool is_inherited (void) const { return rep->is_inherited (); } bool is_persistent (void) const { return rep->is_persistent (); } bool is_added_static (void) const { return rep->is_added_static (); } void mark_local (void) { rep->mark_local (); } void mark_automatic (void) { rep->mark_automatic (); } void mark_formal (void) { rep->mark_formal (); } void mark_hidden (void) { rep->mark_hidden (); } void mark_inherited (void) { rep->mark_inherited (); } void mark_global (void) { rep->mark_global (); } void mark_persistent (void) { rep->mark_persistent (); } void mark_added_static (void) { rep->mark_added_static (); } void unmark_local (void) { rep->unmark_local (); } void unmark_automatic (void) { rep->unmark_automatic (); } void unmark_formal (void) { rep->unmark_formal (); } void unmark_hidden (void) { rep->unmark_hidden (); } void unmark_inherited (void) { rep->unmark_inherited (); } void unmark_global (void) { rep->unmark_global (); } void unmark_persistent (void) { rep->unmark_persistent (); } void unmark_added_static (void) { rep->unmark_added_static (); } void init_persistent (void) { rep->init_persistent (); } void erase_persistent (void) { rep->erase_persistent (); } void invalidate (void) { rep->invalidate (); } scope *decl_scope (void) { return rep->decl_scope (); } unsigned int xstorage_class (void) const { return rep->storage_class; } void set_curr_fcn (octave_user_function *fcn) { rep->set_curr_fcn (fcn); } octave_value dump (void) const { return rep->dump (); } const symbol_record_rep *xrep (void) const { return rep; } private: symbol_record_rep *rep; symbol_record (symbol_record_rep *new_rep) : rep (new_rep) { } }; static symbol_record dummy_symbol_record; // Always access a symbol from the current scope. // Useful for scripts, as they may be executed in more than one scope. class symbol_reference { public: symbol_reference (void) : m_scope (nullptr), m_context (0) { } symbol_reference (const symbol_record& record); symbol_reference (const symbol_record& record, scope *curr_scope, context_id context) : m_scope (curr_scope), m_context (context), m_sym (record) { } symbol_reference (const symbol_reference& ref) = default; symbol_reference& operator = (const symbol_reference& ref) = default; bool is_black_hole (void) const { return ! m_scope; } symbol_table::scope * scope (void) const { update (); return m_scope; } context_id context (void) const { update (); return m_context; } // The name is the same regardless of scope. const std::string& name (void) const { return m_sym.name (); } symbol_record *operator-> (void) { update (); return &m_sym; } symbol_record *operator-> (void) const { update (); return &m_sym; } // can be used to place symbol_reference in maps, we don't overload < as // it doesn't make any sense for symbol_reference struct comparator { bool operator ()(const symbol_reference& lhs, const symbol_reference& rhs) const { return lhs.name () < rhs.name (); } }; private: void update (void) const; mutable symbol_table::scope *m_scope; mutable context_id m_context; mutable symbol_record m_sym; }; class fcn_info { public: typedef std::map<std::string, octave_value>::const_iterator str_val_const_iterator; typedef std::map<std::string, octave_value>::iterator str_val_iterator; private: class fcn_info_rep { public: fcn_info_rep (const std::string& nm) : name (nm), package_name (), local_functions (), private_functions (), class_constructors (), class_methods (), cmdline_function (), autoload_function (), function_on_path (), built_in_function (), count (1) { size_t pos = name.rfind ('.'); if (pos != std::string::npos) { package_name = name.substr (0, pos); name = name.substr (pos+1); } } // No copying! fcn_info_rep (const fcn_info_rep&) = delete; fcn_info_rep& operator = (const fcn_info_rep&) = delete; ~fcn_info_rep (void) = default; octave_value install_local_function (const std::string& file_name); octave_value load_private_function (const std::string& dir_name); octave_value load_class_constructor (void); octave_value load_class_method (const std::string& dispatch_type); octave_value find (const octave_value_list& args, bool local_funcs); octave_value builtin_find (void); octave_value find_method (const std::string& dispatch_type); octave_value find_autoload (void); octave_value find_package (void); octave_value find_user_function (void); bool is_user_function_defined (void) const { return function_on_path.is_defined (); } octave_value find_function (const octave_value_list& args, bool local_funcs) { return find (args, local_funcs); } void install_cmdline_function (const octave_value& f) { cmdline_function = f; } void install_local_function (const octave_value& f, const std::string& file_name) { local_functions[file_name] = f; } void install_user_function (const octave_value& f) { function_on_path = f; } void install_built_in_function (const octave_value& f) { built_in_function = f; } void install_built_in_dispatch (const std::string& klass); template <typename T> void clear_map (std::map<T, octave_value>& map, bool force = false) { typename std::map<T, octave_value>::iterator p = map.begin (); while (p != map.end ()) { if (force || ! p->second.islocked ()) map.erase (p++); else p++; } } void clear_autoload_function (bool force = false) { if (force || ! autoload_function.islocked ()) autoload_function = octave_value (); } // We also clear command line functions here, as these are both // "user defined" void clear_user_function (bool force = false) { clear_autoload_function (force); if (force || ! function_on_path.islocked ()) function_on_path = octave_value (); if (force || ! cmdline_function.islocked ()) cmdline_function = octave_value (); } void clear_mex_function (void) { if (function_on_path.is_mex_function ()) clear_user_function (); } void clear_package (void) { package = octave_value (); } void clear (bool force = false) { clear_map (local_functions, force); clear_map (private_functions, force); clear_map (class_constructors, force); clear_map (class_methods, force); clear_autoload_function (force); clear_user_function (force); clear_package (); } octave_value dump (void) 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; // File name to function object. std::map<std::string, octave_value> local_functions; // Directory name to function object. std::map<std::string, octave_value> private_functions; // Class name to function object. std::map<std::string, octave_value> class_constructors; // Dispatch type to function object. std::map<std::string, octave_value> class_methods; octave_value cmdline_function; octave_value autoload_function; octave_value function_on_path; octave_value package; octave_value built_in_function; refcount<size_t> count; private: octave_value xfind (const octave_value_list& args, bool local_funcs); octave_value x_builtin_find (void); }; public: fcn_info (const std::string& nm = "") : rep (new fcn_info_rep (nm)) { } fcn_info (const fcn_info& fi) : rep (fi.rep) { rep->count++; } fcn_info& operator = (const fcn_info& fi) { if (this != &fi) { if (--rep->count == 0) delete rep; rep = fi.rep; rep->count++; } return *this; } ~fcn_info (void) { if (--rep->count == 0) delete rep; } octave_value find (const octave_value_list& args = octave_value_list (), bool local_funcs = true) { return rep->find (args, local_funcs); } octave_value builtin_find (void) { return rep->builtin_find (); } octave_value find_method (const std::string& dispatch_type) const { return rep->find_method (dispatch_type); } octave_value find_built_in_function (void) const { return rep->built_in_function; } octave_value find_cmdline_function (void) const { return rep->cmdline_function; } octave_value find_autoload (void) { return rep->find_autoload (); } octave_value find_user_function (void) { return rep->find_user_function (); } bool is_user_function_defined (void) const { return rep->is_user_function_defined (); } octave_value find_function (const octave_value_list& args = octave_value_list (), bool local_funcs = true) { return rep->find_function (args, local_funcs); } void install_cmdline_function (const octave_value& f) { rep->install_cmdline_function (f); } void install_local_function (const octave_value& f, const std::string& file_name) { rep->install_local_function (f, file_name); } void install_user_function (const octave_value& f) { rep->install_user_function (f); } void install_built_in_function (const octave_value& f) { rep->install_built_in_function (f); } void install_built_in_dispatch (const std::string& klass) { rep->install_built_in_dispatch (klass); } void clear (bool force = false) { rep->clear (force); } void clear_user_function (bool force = false) { rep->clear_user_function (force); } void clear_autoload_function (bool force = false) { rep->clear_autoload_function (force); } void clear_mex_function (void) { rep->clear_mex_function (); } octave_value dump (void) const { return rep->dump (); } private: fcn_info_rep *rep; }; symbol_table (void) : m_global_symbols (), m_fcn_table (), m_class_precedence_table (), m_parent_map (), m_global_scope (new scope ("global scope")), m_top_scope (new scope ("top scope")), m_current_scope (m_top_scope) { } // No copying! symbol_table (const symbol_table&) = delete; symbol_table& operator = (const symbol_table&) = delete; ~symbol_table (void) { delete m_top_scope; delete m_global_scope; } scope *global_scope (void) { return m_global_scope; } scope *top_scope (void) { return m_top_scope; } scope *current_scope (void) { return m_current_scope; } scope *require_current_scope (const std::string& who) { if (! m_current_scope) error ("%s: missing scope", who.c_str ()); return m_current_scope; } context_id current_context (void) const { return m_current_scope ? m_current_scope->current_context () : 0; } void set_scope (scope *sid) { set_scope_and_context (sid, 0); } void set_scope_and_context (scope *sid, context_id context) { if (sid == m_global_scope) error ("can't set scope to global"); m_current_scope = sid; if (m_current_scope) m_current_scope->set_context (context); } symbol_record find_symbol (const std::string& name, scope *sid) { return sid ? sid->find_symbol (name) : symbol_record (); } symbol_record find_symbol (const std::string& name) { return find_symbol (name, m_current_scope); } void inherit (scope *recipient_scope, scope *donor_scope) { if (recipient_scope) recipient_scope->inherit (donor_scope); } void inherit (scope *recipient_scope) { inherit (recipient_scope, m_current_scope); } bool at_top_level (void) { return m_current_scope == m_top_scope; } // Find a value corresponding to the given name in the table. octave_value find (const std::string& name, const octave_value_list& args = octave_value_list (), bool skip_variables = false, bool local_funcs = true); octave_value builtin_find (const std::string& name); void assign (const std::string& name, const octave_value& value, bool force_add) { if (m_current_scope) m_current_scope->assign (name, value, force_add); } void assign (const std::string& name, const octave_value& value = octave_value ()) { if (m_current_scope) m_current_scope->assign (name, value); } octave_value varval (const std::string& name) { return (m_current_scope ? m_current_scope->varval (name) : octave_value ()); } void global_assign (const std::string& name, const octave_value& value = octave_value ()) { global_symbols_iterator p = m_global_symbols.find (name); if (p == m_global_symbols.end ()) m_global_symbols[name] = value; else p->second = value; } octave_value global_varval (const std::string& name) { global_symbols_const_iterator p = m_global_symbols.find (name); return (p != m_global_symbols.end ()) ? p->second : octave_value (); } void top_level_assign (const std::string& name, const octave_value& value = octave_value ()) { m_top_scope->assign (name, value); } octave_value top_level_varval (const std::string& name) { return m_top_scope->varval (name); } bool is_built_in_function_name (const std::string& name) { octave_value val = find_built_in_function (name); return val.is_defined (); } octave_value find_method (const std::string& name, const std::string& dispatch_type) { fcn_table_const_iterator p = m_fcn_table.find (name); if (p != m_fcn_table.end ()) { octave_value fcn = p->second.find_method (dispatch_type); if (! fcn.is_defined ()) fcn = find_submethod (name, dispatch_type); return fcn; } else { fcn_info finfo (name); octave_value fcn = finfo.find_method (dispatch_type); if (! fcn.is_defined ()) fcn = find_submethod (name, dispatch_type); if (fcn.is_defined ()) m_fcn_table[name] = finfo; return fcn; } } octave_value find_submethod (const std::string& name, const std::string& dispatch_type); octave_value find_built_in_function (const std::string& name) { fcn_table_const_iterator p = m_fcn_table.find (name); return (p != m_fcn_table.end () ? p->second.find_built_in_function () : octave_value ()); } octave_value find_autoload (const std::string& name) { fcn_table_iterator p = m_fcn_table.find (name); return (p != m_fcn_table.end () ? p->second.find_autoload () : octave_value ()); } octave_value find_function (const std::string& name, const octave_value_list& args = octave_value_list (), bool local_funcs = true); octave_value find_user_function (const std::string& name) { fcn_table_iterator p = m_fcn_table.find (name); return (p != m_fcn_table.end () ? p->second.find_user_function () : octave_value ()); } octave_value find_cmdline_function (const std::string& name) { fcn_table_iterator p = m_fcn_table.find (name); return (p != m_fcn_table.end () ? p->second.find_cmdline_function () : octave_value ()); } void install_cmdline_function (const std::string& name, const octave_value& fcn) { fcn_table_iterator p = m_fcn_table.find (name); if (p != m_fcn_table.end ()) { fcn_info& finfo = p->second; finfo.install_cmdline_function (fcn); } else { fcn_info finfo (name); finfo.install_cmdline_function (fcn); m_fcn_table[name] = finfo; } } // Install local function FCN named NAME. FILE_NAME is the name of // the file containing the local function. void install_local_function (const std::string& name, const octave_value& fcn, const std::string& file_name) { fcn_table_iterator p = m_fcn_table.find (name); if (p != m_fcn_table.end ()) { fcn_info& finfo = p->second; finfo.install_local_function (fcn, file_name); } else { fcn_info finfo (name); finfo.install_local_function (fcn, file_name); m_fcn_table[name] = finfo; } } void install_user_function (const std::string& name, const octave_value& fcn) { fcn_table_iterator p = m_fcn_table.find (name); if (p != m_fcn_table.end ()) { fcn_info& finfo = p->second; finfo.install_user_function (fcn); } else { fcn_info finfo (name); finfo.install_user_function (fcn); m_fcn_table[name] = finfo; } } void install_built_in_function (const std::string& name, const octave_value& fcn) { fcn_table_iterator p = m_fcn_table.find (name); if (p != m_fcn_table.end ()) { fcn_info& finfo = p->second; finfo.install_built_in_function (fcn); } else { fcn_info finfo (name); finfo.install_built_in_function (fcn); m_fcn_table[name] = finfo; } } void clear_all (bool force = false) { if (m_current_scope) { m_current_scope->clear_variables (); m_current_scope->clear_global_pattern ("*"); } clear_functions (force); } // This is written as two separate functions instead of a single // function with default values so that it will work properly with // unwind_protect. void clear_functions (bool force = false) { fcn_table_iterator p = m_fcn_table.begin (); while (p != m_fcn_table.end ()) (p++)->second.clear (force); } void clear_function (const std::string& name) { clear_user_function (name); } void clear_symbol (const std::string& name) { // FIXME: are we supposed to do both here? if (m_current_scope) m_current_scope->clear_variable (name); clear_function (name); } void clear_function_pattern (const std::string& pat) { glob_match pattern (pat); fcn_table_iterator p = m_fcn_table.begin (); while (p != m_fcn_table.end ()) { if (pattern.match (p->first)) (p++)->second.clear_user_function (); else p++; } } void clear_symbol_pattern (const std::string& pat) { // FIXME: are we supposed to do both here? if (m_current_scope) m_current_scope->clear_variable_pattern (pat); clear_function_pattern (pat); } void clear_user_function (const std::string& name) { fcn_table_iterator p = m_fcn_table.find (name); if (p != m_fcn_table.end ()) { fcn_info& finfo = p->second; finfo.clear_user_function (); } // FIXME: is this necessary, or even useful? // else // error ("clear: no such function '%s'", name.c_str ()); } // This clears oct and mex files, including autoloads. void clear_dld_function (const std::string& name) { fcn_table_iterator p = m_fcn_table.find (name); if (p != m_fcn_table.end ()) { fcn_info& finfo = p->second; finfo.clear_autoload_function (); finfo.clear_user_function (); } } void clear_mex_functions (void) { fcn_table_iterator p = m_fcn_table.begin (); while (p != m_fcn_table.end ()) (p++)->second.clear_mex_function (); } bool set_class_relationship (const std::string& sup_class, const std::string& inf_class); bool is_superiorto (const std::string& a, const std::string& b); void alias_built_in_function (const std::string& alias, const std::string& name) { octave_value fcn = find_built_in_function (name); if (fcn.is_defined ()) { fcn_info finfo (alias); finfo.install_built_in_function (fcn); m_fcn_table[alias] = finfo; } else panic ("alias: '%s' is undefined", name.c_str ()); } void install_built_in_dispatch (const std::string& name, const std::string& klass) { fcn_table_iterator p = m_fcn_table.find (name); if (p != m_fcn_table.end ()) { fcn_info& finfo = p->second; finfo.install_built_in_dispatch (klass); } else error ("install_built_in_dispatch: '%s' is undefined", name.c_str ()); } void push_context (void) { if (m_current_scope == m_top_scope) error ("invalid call to symtab::push_context"); if (m_current_scope) m_current_scope->push_context (); } // This is written as two separate functions instead of a single // function with default values so that it will work properly with // unwind_protect. void pop_context (void) { if (m_current_scope == m_top_scope) error ("invalid call to symtab::pop_context"); if (m_current_scope) m_current_scope->pop_context (); } // For unwind_protect where a pointer argument is needed. void pop_context (void *) { pop_context (); } std::list<symbol_record> glob (const std::string& pattern) { return (m_current_scope ? m_current_scope->glob (pattern) : std::list<symbol_record> ()); } std::list<symbol_record> glob_global_variables (const std::string& pattern) { std::list<symbol_record> retval; glob_match pat (pattern); for (const auto& nm_val : m_global_symbols) { // We generate a list of symbol_record objects so that the results from // glob_variables and glob_global_variables may be handled the same // way. if (pat.match (nm_val.first)) retval.push_back (symbol_record (m_global_scope, nm_val.first, nm_val.second, symbol_record::global)); } return retval; } std::list<symbol_record> regexp_global_variables (const std::string& pattern) { std::list<symbol_record> retval; octave::regexp pat (pattern); for (const auto& nm_val : m_global_symbols) { // We generate a list of symbol_record objects so that the results from // regexp_variables and regexp_global_variables may be handled the same // way. if (pat.is_match (nm_val.first)) retval.push_back (symbol_record (m_global_scope, nm_val.first, nm_val.second, symbol_record::global)); } return retval; } std::list<symbol_record> glob_variables (const string_vector& patterns) { std::list<symbol_record> retval; if (! m_current_scope) return retval; size_t len = patterns.numel (); for (size_t i = 0; i < len; i++) { std::list<symbol_record> tmp = m_current_scope->glob (patterns[i]); retval.insert (retval.begin (), tmp.begin (), tmp.end ()); } return retval; } std::list<symbol_record> regexp_variables (const string_vector& patterns) { std::list<symbol_record> retval; if (! m_current_scope) return retval; size_t len = patterns.numel (); for (size_t i = 0; i < len; i++) { std::list<symbol_record> tmp = m_current_scope->regexp (patterns[i]); retval.insert (retval.begin (), tmp.begin (), tmp.end ()); } return retval; } std::list<std::string> user_function_names (void) { std::list<std::string> retval; for (const auto& nm_finfo : m_fcn_table) { if (nm_finfo.second.is_user_function_defined ()) retval.push_back (nm_finfo.first); } if (! retval.empty ()) retval.sort (); return retval; } std::list<std::string> global_variable_names (void) { std::list<std::string> retval; for (const auto& nm_val : m_global_symbols) retval.push_back (nm_val.first); retval.sort (); return retval; } std::list<std::string> top_level_variable_names (void) { return (m_top_scope ? m_top_scope->variable_names () : std::list<std::string> ()); } std::list<std::string> variable_names (void) { return (m_current_scope ? m_current_scope->variable_names () : std::list<std::string> ()); } std::list<std::string> built_in_function_names (void) { std::list<std::string> retval; for (const auto& nm_finfo : m_fcn_table) { octave_value fcn = nm_finfo.second.find_built_in_function (); if (fcn.is_defined ()) retval.push_back (nm_finfo.first); } if (! retval.empty ()) retval.sort (); return retval; } std::list<std::string> cmdline_function_names (void) { std::list<std::string> retval; for (const auto& nm_finfo : m_fcn_table) { octave_value fcn = nm_finfo.second.find_cmdline_function (); if (fcn.is_defined ()) retval.push_back (nm_finfo.first); } if (! retval.empty ()) retval.sort (); return retval; } octave_value dump (void) const; void add_to_parent_map (const std::string& classname, const std::list<std::string>& parent_list) { m_parent_map[classname] = parent_list; } std::list<std::string> parent_classes (const std::string& dispatch_type) { std::list<std::string> retval; const_parent_map_iterator it = m_parent_map.find (dispatch_type); if (it != m_parent_map.end ()) retval = it->second; for (const auto& nm : retval) { // Search for parents of parents and append them to the list. // FIXME: should we worry about a circular inheritance graph? std::list<std::string> parents = parent_classes (nm); if (! parents.empty ()) retval.insert (retval.end (), parents.begin (), parents.end ()); } return retval; } octave_user_function * get_curr_fcn (void) { return m_current_scope ? m_current_scope->function () : nullptr; } void cleanup (void); fcn_info * get_fcn_info (const std::string& name) { fcn_table_iterator p = m_fcn_table.find (name); return p != m_fcn_table.end () ? &p->second : nullptr; } class scope { public: typedef std::map<std::string, symbol_table::symbol_record>::const_iterator table_const_iterator; typedef std::map<std::string, symbol_table::symbol_record>::iterator table_iterator; typedef std::map<std::string, octave_value>::const_iterator m_persistent_symbols_const_iterator; typedef std::map<std::string, octave_value>::iterator m_persistent_symbols_iterator; typedef std::map<std::string, octave_value>::const_iterator subfunctions_const_iterator; typedef std::map<std::string, octave_value>::iterator subfunctions_iterator; scope (const std::string& name = "") : m_name (name), m_symbols (), m_persistent_symbols (), m_subfunctions (), m_fcn (nullptr), m_parent (nullptr), m_children (), m_is_nested (false), m_is_static (false), m_context (0) { } // No copying! scope (const scope&) = delete; scope& operator = (const scope&) = delete; ~scope (void) = default; void insert_symbol_record (const symbol_table::symbol_record& sr) { m_symbols[sr.name ()] = sr; } bool is_nested (void) const { return m_is_nested; } void mark_nested (void) { m_is_nested = true; } scope * parent_scope (void) const { return m_parent; } scope * dup (void) const { scope *new_sid = new scope (); for (const auto& nm_sr : m_symbols) new_sid->insert_symbol_record (nm_sr.second.dup (new_sid)); new_sid->m_parent = m_parent; return new_sid; } void set_context (context_id context) { m_context = context; } context_id current_context (void) const { return m_context; } symbol_table::symbol_record find_symbol (const std::string& name) { table_iterator p = m_symbols.find (name); if (p == m_symbols.end ()) return insert (name); else return p->second; } void inherit_internal (scope& donor_scope) { for (auto& nm_sr : m_symbols) { symbol_table::symbol_record& sr = nm_sr.second; if (! (sr.is_automatic () || sr.is_formal ())) { std::string nm = sr.name (); if (nm != "__retval__") { octave_value val = donor_scope.varval (nm); if (val.is_defined ()) { sr.assign (val); sr.mark_inherited (); } } } } } void inherit (scope *donor_scope) { while (donor_scope) { inherit_internal (*donor_scope); if (donor_scope->is_nested ()) donor_scope = donor_scope->parent_scope (); else break; } } octave_value find (const std::string& name, const octave_value_list& args, bool skip_variables, bool local_funcs); octave_value builtin_find (const std::string& name); symbol_table::symbol_record& insert (const std::string& name, bool force_add = false); void rename (const std::string& old_name, const std::string& new_name) { table_iterator p = m_symbols.find (old_name); if (p != m_symbols.end ()) { symbol_table::symbol_record sr = p->second; sr.rename (new_name); m_symbols.erase (p); m_symbols[new_name] = sr; } } void assign (const std::string& name, const octave_value& value, bool force_add) { table_iterator p = m_symbols.find (name); if (p == m_symbols.end ()) { symbol_table::symbol_record& sr = insert (name, force_add); sr.assign (value); } else p->second.assign (value); } void assign (const std::string& name, const octave_value& value = octave_value ()) { assign (name, value, false); } void force_assign (const std::string& name, const octave_value& value) { table_iterator p = m_symbols.find (name); if (p == m_symbols.end ()) { symbol_table::symbol_record& sr = insert (name, true); sr.assign (value); } else p->second.assign (value); } // Use assign (name, value, force_add) instead. // Delete when deprecated varref functions are removed. octave_value& varref (const std::string& name, bool force_add) { table_iterator p = m_symbols.find (name); if (p == m_symbols.end ()) { symbol_table::symbol_record& sr = insert (name, force_add); return sr.varref (); } else return p->second.varref (); } octave_value varval (const std::string& name) const { table_const_iterator p = m_symbols.find (name); return (p != m_symbols.end () ? p->second.varval () : octave_value ()); } void persistent_assign (const std::string& name, const octave_value& value) { m_persistent_symbols_iterator p = m_persistent_symbols.find (name); if (p == m_persistent_symbols.end ()) m_persistent_symbols[name] = value; else p->second = value; } // Use persistent_assign (name, value) instead. // Delete when deprecated varref functions are removed. octave_value& persistent_varref (const std::string& name) { m_persistent_symbols_iterator p = m_persistent_symbols.find (name); return (p == m_persistent_symbols.end () ? m_persistent_symbols[name] : p->second); } octave_value persistent_varval (const std::string& name) { m_persistent_symbols_const_iterator p = m_persistent_symbols.find (name); return (p != m_persistent_symbols.end ()) ? p->second : octave_value (); } void erase_persistent (const std::string& name) { m_persistent_symbols_iterator p = m_persistent_symbols.find (name); if (p != m_persistent_symbols.end ()) m_persistent_symbols.erase (p); } bool is_variable (const std::string& name) const { bool retval = false; table_const_iterator p = m_symbols.find (name); if (p != m_symbols.end ()) { const symbol_table::symbol_record& sr = p->second; retval = sr.is_variable (); } return retval; } void push_context (void) { for (auto& nm_sr : m_symbols) nm_sr.second.push_context (this); } void pop_context (void) { table_iterator tbl_it = m_symbols.begin (); while (tbl_it != m_symbols.end ()) { if (tbl_it->second.pop_context (this) == 0) m_symbols.erase (tbl_it++); else tbl_it++; } } void clear_variables (void) { for (auto& nm_sr : m_symbols) nm_sr.second.clear (this); } void clear_objects (void) { for (auto& nm_sr : m_symbols) { symbol_table::symbol_record& sr = nm_sr.second; octave_value val = sr.varval (); if (val.isobject ()) nm_sr.second.clear (this); } } void clear_global (const std::string& name); void clear_variable (const std::string& name) { table_iterator p = m_symbols.find (name); if (p != m_symbols.end ()) p->second.clear (this); } void clear_global_pattern (const std::string& pat); void clear_variable_pattern (const std::string& pat) { glob_match pattern (pat); for (auto& nm_sr : m_symbols) { symbol_table::symbol_record& sr = nm_sr.second; if (sr.is_defined () || sr.is_global ()) { if (pattern.match (sr.name ())) sr.clear (this); } } } void clear_variable_regexp (const std::string& pat) { octave::regexp pattern (pat); for (auto& nm_sr : m_symbols) { symbol_table::symbol_record& sr = nm_sr.second; if (sr.is_defined () || sr.is_global ()) { if (pattern.is_match (sr.name ())) sr.clear (this); } } } void mark_automatic (const std::string& name) { insert (name).mark_automatic (); } void mark_hidden (const std::string& name) { insert (name).mark_hidden (); } void mark_global (const std::string& name) { insert (name).mark_global (); } std::list<symbol_table::symbol_record> all_variables (bool defined_only = true, unsigned int exclude = symbol_table::symbol_record::hidden) const { std::list<symbol_table::symbol_record> retval; for (const auto& nm_sr : m_symbols) { const symbol_table::symbol_record& sr = nm_sr.second; if ((defined_only && ! sr.is_defined ()) || (sr.xstorage_class () & exclude)) continue; retval.push_back (sr); } return retval; } std::list<symbol_table::symbol_record> glob (const std::string& pattern, bool vars_only = false) const { std::list<symbol_table::symbol_record> retval; glob_match pat (pattern); for (const auto& nm_sr : m_symbols) { if (pat.match (nm_sr.first)) { const symbol_table::symbol_record& sr = nm_sr.second; if (vars_only && ! sr.is_variable ()) continue; retval.push_back (sr); } } return retval; } std::list<symbol_table::symbol_record> regexp (const std::string& pattern, bool vars_only = false) const { std::list<symbol_table::symbol_record> retval; octave::regexp pat (pattern); for (const auto& nm_sr : m_symbols) { if (pat.is_match (nm_sr.first)) { const symbol_table::symbol_record& sr = nm_sr.second; if (vars_only && ! sr.is_variable ()) continue; retval.push_back (sr); } } return retval; } std::list<std::string> variable_names (void) { std::list<std::string> retval; for (const auto& nm_sr : m_symbols) { if (nm_sr.second.is_variable ()) retval.push_back (nm_sr.first); } retval.sort (); return retval; } bool is_local_variable (const std::string& name) const { table_const_iterator p = m_symbols.find (name); return (p != m_symbols.end () && ! p->second.is_global () && p->second.is_defined ()); } bool is_global (const std::string& name) const { table_const_iterator p = m_symbols.find (name); return p != m_symbols.end () && p->second.is_global (); } void install_subfunction (const std::string& name, const octave_value& fval, bool is_nested = false); void install_nestfunction (const std::string& name, const octave_value& fval) { install_subfunction (name, fval, true); } octave_value find_subfunction (const std::string& name) const; void lock_subfunctions (void) { for (auto& nm_sf : m_subfunctions) nm_sf.second.lock (); } void unlock_subfunctions (void) { for (auto& nm_sf : m_subfunctions) nm_sf.second.unlock (); } std::map<std::string, octave_value> subfunctions (void) { return m_subfunctions; } void erase_subfunctions (void) { m_subfunctions.clear (); } void mark_subfunctions_in_scope_as_private (const std::string& class_name); std::list<workspace_element> workspace_info (void) const; octave_value dump (void) const; std::string name (void) const { return m_name; } void cache_name (const std::string& name) { m_name = name; } octave_user_function *function (void) { return m_fcn; } void set_function (octave_user_function *fcn) { m_fcn = fcn; } void set_parent (scope *p) { m_parent = p; } void update_nest (void); bool look_nonlocal (const std::string& name, symbol_table::symbol_record& result); private: // Name for this scope (usually the corresponding filename of the // function corresponding to the scope). std::string m_name; // Map from symbol names to symbol info. std::map<std::string, symbol_table::symbol_record> m_symbols; // Map from names of persistent variables to values. std::map<std::string, octave_value> m_persistent_symbols; // Map from symbol names to subfunctions. std::map<std::string, octave_value> m_subfunctions; // The associated user code (may be null). octave_user_function *m_fcn; // Parent of nested function (may be null). scope *m_parent; // Child nested functions. std::vector<scope*> m_children; // If true, then this scope belongs to a nested function. bool m_is_nested; // If true then no variables can be added. bool m_is_static; context_id m_context; octave_value dump_symbols_map (void) const; }; private: typedef std::map<std::string, octave_value>::const_iterator global_symbols_const_iterator; typedef std::map<std::string, octave_value>::iterator global_symbols_iterator; typedef std::map<std::string, fcn_info>::const_iterator fcn_table_const_iterator; typedef std::map<std::string, fcn_info>::iterator fcn_table_iterator; // Map from names of global variables to values. std::map<std::string, octave_value> m_global_symbols; // Map from function names to function info (private // functions, class constructors, class methods, etc.) // Note that subfunctions are defined in the scope that contains // them. std::map<std::string, fcn_info> m_fcn_table; // Map from class names to set of classes that have lower // precedence. std::map<std::string, std::set<std::string>> m_class_precedence_table; typedef std::map<std::string, std::set<std::string>>::const_iterator class_precedence_table_const_iterator; typedef std::map<std::string, std::set<std::string>>::iterator class_precedence_table_iterator; // Map from class names to parent class names. std::map<std::string, std::list<std::string>> m_parent_map; typedef std::map<std::string, std::list<std::string>>::const_iterator const_parent_map_iterator; typedef std::map<std::string, std::list<std::string>>::iterator parent_map_iterator; scope *m_global_scope; scope *m_top_scope; scope *m_current_scope; octave_value dump_fcn_table_map (void) const; }; extern bool out_of_date_check (octave_value& function, const std::string& dispatch_type = "", bool check_relative = true); extern OCTINTERP_API std::string get_dispatch_type (const octave_value_list& args); extern OCTINTERP_API std::string get_dispatch_type (const octave_value_list& args, builtin_type_t& builtin_type); } #endif