octave: Simplified module loading.

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@13941 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
Karl Wette 2012-11-28 20:22:56 +00:00
commit e60ae2d81d
5 changed files with 141 additions and 159 deletions

View file

@ -5,6 +5,15 @@ See the RELEASENOTES file for a summary of changes in each release.
Version 2.0.9 (in progress)
===========================
2012-11-28: kwwette
[Octave] Simplified module loading: now just the syntax
$ example;
is accepted, which loads functions globally but constants and variables relative to the current scope.
This make module loading behaviour reliably consistent, and reduces problems when loading modules which
depend on other modules which may not have been previously loaded.
*** POTENTIAL INCOMPATIBILITY ***
2012-11-17: wsfulton
[Tcl, Modula3] Add missing support for -outdir.

View file

@ -181,12 +181,7 @@ When Octave is asked to invoke <tt>example</tt>, it will try to find the ".m" or
</p>
<p>
An Octave module can either load its symbols into the global namespace, so that they can be accessed directly without having to type the module name.
Alternatively, an Octave module can be accessed through a local variable, without being loaded globally.
</p>
<p>
To load an Octave module globally, simply type its name:
To load an Octave module, simply type its name:
</p>
<div class="targetlang"><pre>
@ -200,43 +195,6 @@ octave:5&gt; cvar.Foo
ans = 4
</pre></div>
<p>
To access an Octave module through a local variable, without loading it globally, simply assign the module name (e.g. "example") to the desired local variable:
</p>
<div class="targetlang"><pre>
octave:1&gt; example = example;
octave:2&gt; example.gcd(6,9)
ans = 3
octave:3&gt; example.cvar.Foo
ans = 3
</pre></div>
<p>
The variable may have the same name as the module, or a shorter one:
</p>
<div class="targetlang"><pre>
octave:1&gt; ex = example;
octave:2&gt; ex.gcd(6,9)
ans = 3
octave:3&gt; ex.cvar.Foo
ans = 3
</pre></div>
<p>
It is also possible to rename the global variables namespaces with an assignment, as in:
</p>
<div class="targetlang"><pre>
octave:1&gt; example;
octave:2&gt; cvar.gcd(10,4)
ans = 2
octave:3&gt; some_vars = cvar;
octave:4&gt; some_vars.Foo
ans = 3
</pre></div>
<p>
Modules can also be loaded from within functions, even before being loaded in the base context.
If the module is also used in the base context, however, it must first be loaded again:

View file

@ -1,17 +1,7 @@
# file: runme_args.m
# test module loading with arguments
clear all
# access module, no global load
example = example;
assert(example.cvar.ivar == example.ifunc());
clear all
example = example;
assert(example.cvar.ivar == example.ifunc());
clear all
# load module globally
# load module
clear all;
example;
assert(cvar.ivar == ifunc);
assert(exist("example","var"));
@ -21,27 +11,8 @@ assert(cvar.ivar == ifunc);
assert(exist("example","var"));
clear all
# access module in a function, no global load
function testme
example = example;
assert(example.cvar.ivar == example.ifunc());
endfunction
testme
testme
example = example;
assert(example.cvar.ivar == example.ifunc());
clear all
function testme
example = example;
assert(example.cvar.ivar == example.ifunc());
endfunction
testme
testme
example = example;
assert(example.cvar.ivar == example.ifunc());
clear all
# load module in a function globally before base context
clear all;
function testme
example;
assert(cvar.ivar == ifunc);
@ -66,6 +37,7 @@ assert(exist("example","var"));
clear all
# load module in a function globally after base context
clear all;
example;
assert(cvar.ivar == ifunc);
assert(exist("example","var"));
@ -95,17 +67,8 @@ if api_version < 37
exit
endif
# access module with no cvar, no global load
example2 = example2;
assert(example2.ivar == example2.ifunc());
assert(!isglobal("cvar"))
clear all
example2 = example2;
assert(example2.ivar == example2.ifunc());
assert(!isglobal("cvar"))
clear all
# load module with no cvar globally
# load module with no cvar
clear all;
example2;
assert(example2.ivar == ifunc);
assert(exist("example2","var"));

View file

@ -20,13 +20,74 @@
%insert(initbeforefunc) %{
static void SWIG_init_user(octave_swig_type* module_ns);
static bool SWIG_init_user(octave_swig_type* module_ns);
SWIGINTERN void SWIG_Octave_InstallFunction(octave_function *octloadfcn, std::string name) {
octave_value_list args;
args.append(name);
args.append(octloadfcn->fcn_file_name());
feval("autoload", args, 0);
SWIGINTERN bool SWIG_Octave_LoadModule(std::string name) {
bool retn;
{
#if OCTAVE_API_VERSION_NUMBER < 38
unwind_protect::begin_frame("SWIG_Octave_LoadModule");
unwind_protect_int(error_state);
unwind_protect_int(warning_state);
unwind_protect_bool(discard_error_messages);
unwind_protect_bool(discard_warning_messages);
#else
unwind_protect frame;
frame.protect_var(error_state);
frame.protect_var(warning_state);
frame.protect_var(discard_error_messages);
frame.protect_var(discard_warning_messages);
#endif
error_state = 0;
warning_state = 0;
discard_error_messages = true;
discard_warning_messages = true;
feval(name, octave_value_list(), 0);
retn = (error_state == 0);
#if OCTAVE_API_VERSION_NUMBER < 38
unwind_protect::run_frame("SWIG_Octave_LoadModule");
#endif
}
if (!retn) {
error(SWIG_name_d ": could not load module `%s'", name.c_str());
}
return retn;
}
SWIGINTERN bool SWIG_Octave_InstallFunction(octave_function *octloadfcn, std::string name) {
bool retn;
{
#if OCTAVE_API_VERSION_NUMBER < 38
unwind_protect::begin_frame("SWIG_Octave_InstallFunction");
unwind_protect_int(error_state);
unwind_protect_int(warning_state);
unwind_protect_bool(discard_error_messages);
unwind_protect_bool(discard_warning_messages);
#else
unwind_protect frame;
frame.protect_var(error_state);
frame.protect_var(warning_state);
frame.protect_var(discard_error_messages);
frame.protect_var(discard_warning_messages);
#endif
error_state = 0;
warning_state = 0;
discard_error_messages = true;
discard_warning_messages = true;
octave_value_list args;
args.append(name);
args.append(octloadfcn->fcn_file_name());
error_state = 0;
feval("autoload", args, 0);
retn = (error_state == 0);
#if OCTAVE_API_VERSION_NUMBER < 38
unwind_protect::run_frame("SWIG_Octave_InstallFunction");
#endif
}
if (!retn) {
error(SWIG_name_d ": could not load function `%s'", name.c_str());
}
return retn;
}
static const char *const subclass_usage = "-*- texinfo -*- \n\
@ -44,7 +105,7 @@ DEFUN_DLD( subclass, args, nargout, subclass_usage ) {
octave_swig_ref *osr = static_cast < octave_swig_ref *>(args(j).internal_rep());
octave_swig_type *ost = osr->get_ptr();
if (!ost->is_owned()) {
error("cannot subclass object not constructed on octave side");
error("subclass: cannot subclass object not constructed on octave side");
return octave_value_list();
}
top->merge(*ost);
@ -52,13 +113,13 @@ DEFUN_DLD( subclass, args, nargout, subclass_usage ) {
top->assign(args(j).fcn_handle_value()->fcn_name(), args(j));
} else if (args(j).is_string()) {
if (j + 1 >= args.length()) {
error("member assignments must be of string,value form");
error("subclass: member assignments must be of string,value form");
return octave_value_list();
}
top->assign(args(j).string_value(), args(j + 1));
++j;
} else {
error("invalid arguments to subclass()");
error("subclass: invalid arguments to subclass()");
return octave_value_list();
}
}
@ -72,12 +133,12 @@ Return the underlying C/C++ type name of a SWIG-wrapped object.\n\
DEFUN_DLD( swig_type, args, nargout, swig_type_usage ) {
if (args.length() != 1) {
error("swig_type() must be called with only a single object");
error("swig_type: must be called with only a single object");
return octave_value_list();
}
octave_swig_type *ost = Swig::swig_value_deref(args(0));
if (!ost) {
error("object is not a swig_ref");
error("swig_type: object is not a swig_ref");
return octave_value_list();
}
return octave_value(ost->swig_type_name());
@ -91,7 +152,7 @@ otherwise return `<unknown>'.\n\
DEFUN_DLD( swig_typequery, args, nargout, swig_typequery_usage ) {
if (args.length() != 1 || !args(0).is_string()) {
error("swig_typequery() must be called with single string argument");
error("swig_typequery: must be called with single string argument");
return octave_value_list();
}
swig_module_info *module = SWIG_GetModule(0);
@ -108,14 +169,14 @@ Return the underlying C/C++ pointer of a SWIG-wrapped object.\n\
DEFUN_DLD( swig_this, args, nargout, swig_this_usage ) {
if (args.length() != 1) {
error("swig_this() must be called with only a single object");
error("swig_this: must be called with only a single object");
return octave_value_list();
}
if (args(0).is_matrix_type() && args(0).rows() == 0 && args(0).columns() == 0)
return octave_value(octave_uint64(0));
octave_swig_type *ost = Swig::swig_value_deref(args(0));
if (!ost) {
error("object is not a swig_ref");
error("swig_this: object is not a swig_ref");
return octave_value_list();
}
return octave_value(octave_uint64((unsigned long long) ost->swig_this()));
@ -124,42 +185,34 @@ DEFUN_DLD( swig_this, args, nargout, swig_this_usage ) {
static const char *const SWIG_name_usage = "-*- texinfo -*- \n\
@deftypefn {Loadable Module} {} " SWIG_name_d "\n\
Loads the SWIG-generated module `" SWIG_name_d "'.\n\
\n\
To load the module into the global namespace:\n\
@example\n\
" SWIG_name_d ";\n\
@end example\n\
To access the module through a local variable, without loading it globally:\n\
@example\n\
" SWIG_name_d " = " SWIG_name_d ";\n\
@end example\n\
To access the module locally through a variable named, e.g. @var{modl}:\n\
@example\n\
@var{modl} = " SWIG_name_d ";\n\
@end example\n\
@end deftypefn";
DEFUN_DLD( SWIG_name, args, nargout, SWIG_name_usage ) {
static octave_swig_type* module_ns = 0;
octave_value_list retval;
// workaround to prevent octave seg-faulting on exit: set Octave exit function
// octave_exit to _Exit, which exits immediately without trying to cleanup memory.
// definitely affects version 3.2.*, not sure about 3.3.*, seems to be fixed in
// version 3.4.* and above. can be turned off with macro definition.
#ifndef SWIG_OCTAVE_NO_SEGFAULT_HACK
#if 36 < OCTAVE_API_VERSION_NUMBER && OCTAVE_API_VERSION_NUMBER < 45
octave_exit = ::_Exit;
#endif
#endif
// check for no input and output args
if (args.length() != 0 || nargout != 0) {
print_usage();
return octave_value_list();
}
// create module on first function call
if (!module_ns) {
// workaround to prevent octave seg-faulting on exit: set Octave exit function
// octave_exit to _Exit, which exits immediately without trying to cleanup memory.
// definitely affects version 3.2.*, not sure about 3.3.*, seems to be
// fixed in version 3.4.* and above. can be turned off with macro def.
#ifndef SWIG_OCTAVE_NO_SEGFAULT_HACK
#if 36 < OCTAVE_API_VERSION_NUMBER && OCTAVE_API_VERSION_NUMBER < 45
octave_exit = ::_Exit;
#endif
#endif
// workaround bug in octave where installing global variable of custom type and then
// exiting without explicitly clearing the variable causes octave to segfault.
#if OCTAVE_API_VERSION_NUMBER >= 37
#if OCTAVE_API_VERSION_NUMBER > 36
octave_value_list eval_args;
eval_args.append("base");
eval_args.append("function __swig_atexit__; "
@ -182,10 +235,18 @@ DEFUN_DLD( SWIG_name, args, nargout, SWIG_name_usage ) {
octave_function *me = octave_call_stack::current();
SWIG_Octave_InstallFunction(me, "swig_type");
SWIG_Octave_InstallFunction(me, "swig_typequery");
SWIG_Octave_InstallFunction(me, "swig_this");
SWIG_Octave_InstallFunction(me, "subclass");
if (!SWIG_Octave_InstallFunction(me, "swig_type")) {
return octave_value_list();
}
if (!SWIG_Octave_InstallFunction(me, "swig_typequery")) {
return octave_value_list();
}
if (!SWIG_Octave_InstallFunction(me, "swig_this")) {
return octave_value_list();
}
if (!SWIG_Octave_InstallFunction(me, "subclass")) {
return octave_value_list();
}
octave_swig_type* cvar_ns=0;
if (std::string(SWIG_global_name) != ".") {
@ -219,7 +280,11 @@ DEFUN_DLD( SWIG_name, args, nargout, SWIG_name_usage ) {
(new octave_swig_type(0,swig_types[j])));
}
SWIG_init_user(module_ns);
if (!SWIG_init_user(module_ns)) {
delete module_ns;
module_ns=0;
return octave_value_list();
}
SWIG_InstallOps(octave_swig_ref::static_type_id());
@ -231,38 +296,25 @@ DEFUN_DLD( SWIG_name, args, nargout, SWIG_name_usage ) {
}
// return module if asked for
if (args.length() == 0 && nargout == 1) {
retval = octave_value(module_ns->as_value());
}
octave_function *me = octave_call_stack::current();
// if call with not output arguments, load globally
else if (args.length() == 0 && nargout == 0) {
octave_function *me = octave_call_stack::current();
octave_swig_type::swig_member_const_iterator mb;
for (mb = module_ns->swig_members_begin(); mb != module_ns->swig_members_end(); ++mb) {
if (mb->second.first && mb->second.first->method) {
SWIG_Octave_InstallFunction(me, mb->first);
}
else if (mb->second.second.is_defined()) {
SWIG_Octave_SetGlobalValue(mb->first, mb->second.second);
SWIG_Octave_LinkGlobalValue(mb->first);
octave_swig_type::swig_member_const_iterator mb;
for (mb = module_ns->swig_members_begin(); mb != module_ns->swig_members_end(); ++mb) {
if (mb->second.first && mb->second.first->method) {
if (!SWIG_Octave_InstallFunction(me, mb->first)) {
return octave_value_list();
}
}
SWIG_Octave_SetGlobalValue(SWIG_name_d, module_ns->as_value());
SWIG_Octave_LinkGlobalValue(SWIG_name_d);
else if (mb->second.second.is_defined()) {
SWIG_Octave_SetGlobalValue(mb->first, mb->second.second);
SWIG_Octave_LinkGlobalValue(mb->first);
}
}
// otherwise print usage
else {
print_usage();
}
SWIG_Octave_SetGlobalValue(SWIG_name_d, module_ns->as_value());
SWIG_Octave_LinkGlobalValue(SWIG_name_d);
return retval;
return octave_value_list();
}

View file

@ -207,7 +207,7 @@ public:
Printf(f_runtime, "\n");
Printf(s_global_tab, "\nstatic const struct swig_octave_member swig_globals[] = {\n");
Printf(f_init, "static void SWIG_init_user(octave_swig_type* module_ns)\n{\n");
Printf(f_init, "static bool SWIG_init_user(octave_swig_type* module_ns)\n{\n");
if (!CPlusPlus)
Printf(f_header,"extern \"C\" {\n");
@ -223,7 +223,7 @@ public:
if (directorsEnabled())
Swig_insert_file("director.swg", f_runtime);
Printf(f_init, "}\n");
Printf(f_init, "return true;\n}\n");
Printf(s_global_tab, "{0,0,0,0,0}\n};\n");
Printv(f_wrappers, s_global_tab, NIL);
@ -393,7 +393,7 @@ public:
virtual int importDirective(Node *n) {
String *modname = Getattr(n, "module");
if (modname)
Printf(f_init, "feval(\"%s\",octave_value_list(),1);\n", modname);
Printf(f_init, "if (!SWIG_Octave_LoadModule(\"%s\")) return false;\n", modname);
return Language::importDirective(n);
}