making setting immutables an error

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@9626 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
Mark Gossage 2006-12-21 04:53:12 +00:00
commit bc08e0f335
6 changed files with 90 additions and 39 deletions

View file

@ -1,6 +1,10 @@
Version 1.3.32 (in progress)
============================
12/21/2006: mgossage
[Lua] Update to throw errors when setting immutables,
and allowing user addition of module variables.
12/20/2006: wsfulton
Fix typedef'd variable wrappers that use %naturalvar, eg, std::string.

View file

@ -311,20 +311,39 @@ Its is therefore not possible to 'move' the global variable into the global name
4
</pre></div>
<p>
If a variable is marked with the immutable directive then any attempts to set this variable are silently ignored.
If a variable is marked with the %immutable directive then any attempts to set this variable will cause an lua error. Given a global variable:
</p>
<div class="code"><pre>%module example
%immutable;
extern double Foo;
%mutable;
</pre></div>
<p>
SWIG will generate the <tt>example.Foo_get()</tt> but instead of a set function an error function will be called instead.
</p>
<div class="targetlang"><pre>
&gt; print(e.Foo) -- reading works ok
4
&gt; example.Foo=40 -- but writing does not
This variable is immutable
stack traceback:
[C]: ?
[C]: ?
stdin:1: in main chunk
[C]: ?
</pre></div>
<p>
For those people who would rather that SWIG silently ignore the setting of immutables (as previous versions of the lua bindings did), adding a <tt>-DSWIGLUA_IGNORE_SET_IMMUTABLE</tt> compile option will remove this.
</p>
<p>
Another interesting feature is that it is not possible to add new values into the module from within the interpreter, this is because of the metatable to deal with global variables. It is possible (though not recommended) to use rawset() to add a new value.
Unlike earlier versions of the binding, it is now possible to add new functions or variables to the module, just as if it were a normal table. This does allow the user to rename/remove existing functions and constants (but not linked variables, mutable or immutable). Therefore users are recommended to be careful when doing so.
</p>
<div class="targetlang"><pre>
&gt; -- example.PI does not exist
&gt; print(example.PI)
nil
&gt; example.PI=3.142 -- assign failed, example.PI does still not exist
&gt; print(example.PI)
nil
&gt; -- a rawset will work, after this the value is added
&gt; rawset(example,"PI",3.142)
&gt; example.PI=3.142 -- new value added
&gt; print(example.PI)
3.142
</pre></div>
@ -426,7 +445,7 @@ userdata: 003FA320
Like the pointer in the previous section, this is held as a userdata. However, additional features have been added to make this more usable. SWIG creates some accessor/mutator functions <tt>Point_set_x()</tt> and <tt>Point_get_x()</tt>. These will be wrappered, and then added to the metatable added to the userdata. This provides the natural access to the member variables that were shown above (see end of the document for full details).
</p>
<p>
<tt>const</tt> members of a structure are read-only. Data members can also be forced to be read-only using the immutable directive. As with other immutable's, setting attempts will be silently ignored. For example:
<tt>const</tt> members of a structure are read-only. Data members can also be forced to be read-only using the immutable directive. As with other immutable's, setting attempts will be cause an error. For example:
</p>
<div class="code"><pre>struct Foo {
...
@ -999,7 +1018,8 @@ function __newindex(mod,name,value)
if not s then return end
local f=s[name] -- looks for the function
-- calls it to set the value
if type(f)=="function" then f(value) end
if type(f)=="function" then f(value)
else rawset(mod,name,value) end
end
</pre></div>
<p>

View file

@ -55,15 +55,20 @@ example.print_vars()
print "\nNow I'm going to try and modify some read only variables";
print " Tring to set 'path' to 'Whoa!'";
example.path = "Whoa!"
print " This request was silently ignored by Lua. "
print " But the data has not been changed"
print("path =", example.path)
if pcall(function() example.path = "Whoa!" end)==true then
print " Thats funny, it didn't give an error!"
else
print " It gave an error, as it should"
end
print(" Just checking the value: path =", example.path)
print " Trying to set 'status' to '0'";
example.status = 0
print " Again silently ignored"
print("status =", example.status)
if pcall(function() example.status = 0 end)==true then
print " Thats funny, it didn't give an error!"
else
print " It gave an error, as it should"
end
print(" Just checking the value: status =", example.status)
print "\nI'm going to try and update a structure variable.\n"

View file

@ -85,8 +85,8 @@ struc=Structure()
assert(type(struc.MemberString2)=="string") -- typemaps make this a string
assert(type(struc.ConstMemberString)=="string")
-- set them
struc.ConstMemberString="c" -- silently ignored
-- set a const (should fail with error)
assert(pcall(function () struc.ConstMemberString="c" end)==false)
--print(struc.MemberString:data(),struc.MemberString2,struc.ConstMemberString:data())
--check type again
@ -100,9 +100,9 @@ assert(type(struc.ConstMemberString)=="string")
assert(type(li_std_string.Structure_StaticMemberString2)=="string")
assert(type(li_std_string.Structure_ConstStaticMemberString)=="string")
-- try setting
-- try setting (should fail with error)
--li_std_string.Structure_StaticMemberString2='e'
li_std_string.Structure_ConstStaticMemberString='f' -- silently ignored
assert(pcall(function () li_std_string.Structure_ConstStaticMemberString='f' end)==false)
--[[print(li_std_string.Structure_StaticMemberString:data(),
li_std_string.Structure_StaticMemberString2,
li_std_string.Structure_ConstStaticMemberString:data())]]
@ -111,4 +111,3 @@ li_std_string.Structure_ConstStaticMemberString='f' -- silently ignored
assert(type(li_std_string.Structure_StaticMemberString)=="string")
assert(type(li_std_string.Structure_StaticMemberString2)=="string")
assert(type(li_std_string.Structure_ConstStaticMemberString)=="string")

View file

@ -125,13 +125,27 @@ typedef struct {
#ifdef __cplusplus
/* Special helper for member function pointers
it gets the address, casts it, then dereferences it */
#define SWIG_mem_fn_as_voidptr(a) (*((char**)&(a)))
//#define SWIG_mem_fn_as_voidptr(a) (*((char**)&(a)))
#endif
/* -----------------------------------------------------------------------------
* global variable support code: modules
* ----------------------------------------------------------------------------- */
/* this function is called when trying to set an immutable.
default value is to print an error.
This can removed with a compile flag SWIGLUA_IGNORE_SET_IMMUTABLE */
SWIGINTERN int SWIG_Lua_set_immutable(lua_State* L)
{
/* there should be 1 param passed in: the new value */
#ifndef SWIGLUA_IGNORE_SET_IMMUTABLE
lua_pop(L,1); /* remove it */
lua_pushstring(L,"This variable is immutable");
lua_error(L);
#endif
return 0; /* should not return anything */
}
/* the module.get method used for getting linked data */
SWIGINTERN int SWIG_Lua_module_get(lua_State* L)
{
@ -192,10 +206,11 @@ SWIGINTERN int SWIG_Lua_module_set(lua_State* L)
lua_call(L,1,0);
return 0;
}
lua_pop(L,1); /* remove the top */
}
lua_pop(L,1); /* remove the .set */
return 0;
lua_settop(L,3); /* reset back to start */
/* we now have the table, key & new value, so just set directly */
lua_rawset(L,1); /* add direct */
return 0;
}
/* registering a module in lua */

View file

@ -678,18 +678,27 @@ only WRT this variable will look into this later.
NEW LANGUAGE NOTE:END ************************************************/
REPORT("variableWrapper", n);
String *iname = Getattr(n, "sym:name");
SwigType *type = Getattr(n, "type");
// let SWIG generate the wrappers
int result = Language::variableWrapper(n);
// normally SWIG will generate 2 wrappers, a get and a set
// but in certain scenarios (immutable, or if its arrays), it will not
String *getName = Swig_name_wrapper(Swig_name_get(iname));
String *setName = 0;
if (is_assignable(n) == false || SwigType_isarray(type)) {
// TODO: how about calling a 'this is not settable' error message?
setName = NewString("0");
} else {
// checking whether it can be set to or not appears to be a very error prone issue
// I refered to the Language::variableWrapper() to find this out
bool assignable=is_assignable(n);
SwigType *type = Getattr(n, "type");
String *tm = Swig_typemap_lookup_new("globalin", n, iname, 0);
if (!tm && SwigType_isarray(type))
assignable=false;
Delete(tm);
if (assignable) {
setName = Swig_name_wrapper(Swig_name_set(iname));
} else {
// TODO: how about calling a 'this is not settable' error message?
setName = NewString("SWIG_Lua_set_immutable"); // error message
//setName = NewString("0");
}
// register the variable
Printf(s_var_tab, "%s{ \"%s\", %s, %s },\n", tab4, iname, getName, setName);
@ -960,20 +969,19 @@ NEW LANGUAGE NOTE:END ************************************************/
virtual int membervariableHandler(Node *n) {
// REPORT("membervariableHandler",n);
String *symname = Getattr(n, "sym:name");
String *rname;
String *gname, *sname;
Language::membervariableHandler(n);
Printv(s_attr_tab, tab4, "{ \"", symname, "\",", NIL);
rname = Swig_name_wrapper(Swig_name_get(Swig_name_member(class_name, symname)));
Printv(s_attr_tab, rname, ", ", NIL);
Delete(rname);
gname = Swig_name_wrapper(Swig_name_get(Swig_name_member(class_name, symname)));
if (!GetFlag(n, "feature:immutable")) {
rname = Swig_name_wrapper(Swig_name_set(Swig_name_member(class_name, symname)));
Printv(s_attr_tab, rname, "},\n", NIL);
Delete(rname);
sname = Swig_name_wrapper(Swig_name_set(Swig_name_member(class_name, symname)));
} else {
Printf(s_attr_tab, "0 },\n");
//sname = NewString("0");
sname = NewString("SWIG_Lua_set_immutable"); // error message
}
Printf(s_attr_tab,"%s{ \"%s\", %s, %s},\n",tab4,symname,gname,sname);
Delete(gname);
Delete(sname);
return SWIG_OK;
}