view libinterp/corefcn/scope.cc @ 24263:3b302b2890d7

disentangle symbol_record, scope, and fcn_info from symbol_table class * fcn-info.cc, fcn-info.h, scope.cc, scope.h, symrec.cc, symrec.h: New files extracted from symtab.h and symtab.cc. * libinterp/corefcn/module.mk: Update. * symrec.cc (symbol_record::symbol_record_rep::xglobal_varref): Don't access private symbol_table internals directly. * scope.h, scope.cc (scope::find, scope::builtin_find, scope::clear_global, scope::clear_global_pattern): Don't access private symbol_table internals directly. * symtab.h, symtab.cc (symbol_table::builtin_find): Don't forward to current scope. Look directly in fcn_info table. (symbol_table::global_varref, symbol_table::fcn_table_find, symbol_table::erase_global, symbol_table::erase_global_pattern): New functions. * scope.h (scope::context_id): New typedef. * symrec.h (symbol_record::context_id): New typedef. * symtab.h (symbol_table::context_id): Update. * symtab.h, symtab.cc (symbol_table::dummy_octave_value): Delete static data member. * symtab.h (symbol_table::context_id): Delete typedef. (symbol_table::symbol_record, symbol_table::scope, symbol_table::fcn_info): New typedefs.
author John W. Eaton <jwe@octave.org>
date Thu, 16 Nov 2017 16:06:31 -0500
parents
children
line wrap: on
line source

/*

Copyright (C) 1993-2017 John W. Eaton
Copyright (C) 2009 VZLU Prague, a.s.

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 (HAVE_CONFIG_H)
#  include "config.h"
#endif

#include <sstream>

#include "fcn-info.h"
#include "interpreter-private.h"
#include "interpreter.h"
#include "ov-fcn.h"
#include "ov-usr-fcn.h"
#include "scope.h"
#include "symrec.h"
#include "symtab.h"
#include "utils.h"

namespace octave
{
  octave_value
  scope::find (const std::string& name, const octave_value_list& args,
               bool skip_variables, bool local_funcs)
  {
    // Variable.

    symbol_table& symtab
      = __get_symbol_table__ ("scope::find");

    if (! skip_variables)
      {
        table_iterator p = m_symbols.find (name);

        if (p != m_symbols.end ())
          {
            symbol_record sr = p->second;

            if (sr.is_global ())
              return symtab.global_varval (name);
            else
              {
                octave_value val = sr.varval ();

                if (val.is_defined ())
                  return val;
              }
          }
      }

    if (local_funcs)
      {
        // Subfunction.  I think it only makes sense to check for
        // subfunctions if we are currently executing a function defined
        // from a .m file.

        octave_value fcn = find_subfunction (name);

        if (fcn.is_defined ())
          return fcn;
      }

    return symtab.fcn_table_find (name, args, local_funcs);
  }

  symbol_record&
  scope::insert (const std::string& name, bool force_add)
  {
    table_iterator p = m_symbols.find (name);

    if (p == m_symbols.end ())
      {
        symbol_record ret (this, name);

        if (m_is_nested && m_parent && m_parent->look_nonlocal (name, ret))
          return m_symbols[name] = ret;
        else
          {
            if (m_is_static && ! force_add)
              ret.mark_added_static ();

            return m_symbols[name] = ret;
          }
      }
    else
      return p->second;
  }

  void
  scope::clear_global (const std::string& name)
  {
    table_iterator p = m_symbols.find (name);

    if (p != m_symbols.end ())
      {
        symbol_record& sr = p->second;

        if (sr.is_global ())
          sr.unmark_global ();
      }

    symbol_table& symtab
      = __get_symbol_table__ ("scope::clear_global");

    symtab.erase_global (name);
  }

  void
  scope::clear_global_pattern (const std::string& pat)
  {
    glob_match pattern (pat);

    for (auto& nm_sr : m_symbols)
      {
        symbol_record& sr = nm_sr.second;

        if (sr.is_global () && pattern.match (sr.name ()))
          sr.unmark_global ();
      }

    symbol_table& symtab
      = __get_symbol_table__ ("scope::clear_global_pattern");

    symtab.erase_global_pattern (pattern);
  }

  std::list<workspace_element>
  scope::workspace_info (void) const
  {
    std::list<workspace_element> retval;

    for (const auto& nm_sr : m_symbols)
      {
        std::string nm = nm_sr.first;
        symbol_record sr = nm_sr.second;

        if (! sr.is_hidden ())
          {
            octave_value val = sr.varval ();

            if (val.is_defined ())
              {
                // FIXME: fix size for objects, see kluge in variables.cc
                //dim_vector dv = val.dims ();
                octave_value tmp = val;
                Matrix sz = tmp.size ();
                dim_vector dv = dim_vector::alloc (sz.numel ());
                for (octave_idx_type i = 0; i < dv.ndims (); i++)
                  dv(i) = sz(i);

                char storage = ' ';
                if (sr.is_global ())
                  storage = 'g';
                else if (sr.is_persistent ())
                  storage = 'p';
                else if (sr.is_automatic ())
                  storage = 'a';
                else if (sr.is_formal ())
                  storage = 'f';
                else if (sr.is_hidden ())
                  storage = 'h';
                else if (sr.is_inherited ())
                  storage = 'i';

                std::ostringstream buf;
                val.short_disp (buf);
                std::string short_disp_str = buf.str ();

                workspace_element elt (storage, nm, val.class_name (),
                                       short_disp_str, dv.str (),
                                       val.iscomplex ());

                retval.push_back (elt);
              }
          }
      }

    return retval;
  }

  octave_value
  scope::dump (void) const
  {
    std::map<std::string, octave_value> m
      = {{ "name", m_name },
         { "symbols", dump_symbols_map () },
         { "persistent_variables", m_persistent_symbols },
         { "subfunctions", dump_function_map (m_subfunctions) }};

    return octave_value (m);
  }

  octave_value
  scope::dump_symbols_map (void) const
  {
    std::map<std::string, octave_value> info_map;

    for (const auto& nm_sr : m_symbols)
      {
        std::string nm = nm_sr.first;
        const symbol_record& sr = nm_sr.second;
        info_map[nm] = sr.dump ();
      }

    return octave_value (info_map);
  }

  void
  scope::install_subfunction (const std::string& name,
                              const octave_value& fval, bool is_nested)
  {
    m_subfunctions[name] = fval;

    // This can be simpler once the scope object is stored in the function
    // object...
    octave_user_function *fcn = fval.user_function_value ();

    scope *fcn_scope = fcn->scope ();

    fcn_scope->set_parent (this);

    if (is_nested)
      {
        m_children.push_back (fcn_scope);

        fcn->mark_as_nested_function ();

        fcn_scope->m_is_nested = true;
      }

  }

  octave_value
  scope::find_subfunction (const std::string& name) const
  {
    subfunctions_const_iterator p = m_subfunctions.find (name);

    if (p != m_subfunctions.end ())
      return p->second;

    if (m_parent)
      return m_parent->find_subfunction (name);

    return octave_value ();
  }

  void
  scope::mark_subfunctions_in_scope_as_private (const std::string& class_name)
  {
    for (auto& nm_sf : m_subfunctions)
      {
        octave_function *fcn = nm_sf.second.function_value ();

        if (fcn)
          fcn->mark_as_private_function (class_name);
      }
  }

  void
  scope::set_parent (scope *p)
  {
    m_parent = p;

    if (m_parent)
      {
        // If m_parent is the top-level scope, there will be no parent
        // function.

        octave_function *current_fcn = function ();

        if (current_fcn && current_fcn->is_anonymous_function ())
          {
            octave_function *parent_fcn = m_parent->function ();

            if (parent_fcn)
              m_parent_fcn = octave_value (parent_fcn, true);
          }
      }
  }

  void
  scope::update_nest (void)
  {
    if (m_parent)
      {
        // fix bad symbol_records
        for (auto& nm_sr : m_symbols)
          {
            symbol_record& ours = nm_sr.second;

            if (! ours.is_formal ()
                && m_is_nested && m_parent->look_nonlocal (nm_sr.first, ours))
              {
                if (ours.is_global () || ours.is_persistent ())
                  error ("global and persistent may only be used in the topmost level in which a nested variable is used");
              }
            else
              ours.set_curr_fcn (m_fcn);
          }

        // The scopes of nested functions are static.
        m_is_static = true;
      }
    else if (m_children.size ())
      {
        // Parents of nested functions have static scopes.
        m_is_static = true;

        for (auto& nm_sr : m_symbols)
          nm_sr.second.set_curr_fcn (m_fcn);
      }

    for (auto& symtab_p : m_children)
      symtab_p->update_nest ();
  }

  bool
  scope::look_nonlocal (const std::string& name, symbol_record& result)
  {
    table_iterator p = m_symbols.find (name);
    if (p == m_symbols.end ())
      {
        if (m_is_nested && m_parent)
          return m_parent->look_nonlocal (name, result);
      }
    else if (! p->second.is_automatic ())
      {
        result.bind_fwd_rep (p->second);
        return true;
      }

    return false;
  }

  void
  scope::bind_script_symbols (scope *curr_scope)
  {
    for (auto& nm_sr : m_symbols)
      nm_sr.second.bind_fwd_rep (curr_scope->find_symbol (nm_sr.first));
  }

  void
  scope::unbind_script_symbols (void)
  {
    for (auto& nm_sr : m_symbols)
      nm_sr.second.unbind_fwd_rep ();
  }
}