diff --git a/CHANGES.current b/CHANGES.current index 19912fde6..1675f878b 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -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. diff --git a/Doc/Manual/Octave.html b/Doc/Manual/Octave.html index b8cf02a77..0340c2fd5 100644 --- a/Doc/Manual/Octave.html +++ b/Doc/Manual/Octave.html @@ -181,12 +181,7 @@ When Octave is asked to invoke example, it will try to find the ".m" or

-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. -

- -

-To load an Octave module globally, simply type its name: +To load an Octave module, simply type its name:

@@ -200,43 +195,6 @@ octave:5> cvar.Foo
 ans =  4
 
-

-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: -

- -
-octave:1> example = example;
-octave:2> example.gcd(6,9)
-ans =  3
-octave:3> example.cvar.Foo
-ans =  3
-
- -

-The variable may have the same name as the module, or a shorter one: -

- -
-octave:1> ex = example;
-octave:2> ex.gcd(6,9)
-ans =  3
-octave:3> ex.cvar.Foo
-ans =  3
-
- -

-It is also possible to rename the global variables namespaces with an assignment, as in: -

- -
-octave:1> example;
-octave:2> cvar.gcd(10,4)
-ans =  2
-octave:3> some_vars = cvar;
-octave:4> some_vars.Foo
-ans =  3
-
-

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: diff --git a/Examples/octave/module_load/runme.m b/Examples/octave/module_load/runme.m index 16b437ee8..0fda218cd 100644 --- a/Examples/octave/module_load/runme.m +++ b/Examples/octave/module_load/runme.m @@ -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")); diff --git a/Lib/octave/octruntime.swg b/Lib/octave/octruntime.swg index 16ad3f7c9..66b6e265a 100644 --- a/Lib/octave/octruntime.swg +++ b/Lib/octave/octruntime.swg @@ -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 `'.\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(); } diff --git a/Source/Modules/octave.cxx b/Source/Modules/octave.cxx index 7d27c1095..5758e38c3 100644 --- a/Source/Modules/octave.cxx +++ b/Source/Modules/octave.cxx @@ -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); }