1.1 --- a/generator.py Fri Dec 09 23:30:41 2016 +0100
1.2 +++ b/generator.py Fri Dec 09 23:51:47 2016 +0100
1.3 @@ -56,6 +56,7 @@
1.4 # NOTE: These must be synchronised with the library.
1.5
1.6 function_type = "__builtins__.core.function"
1.7 + string_type = "__builtins__.str.string"
1.8 type_type = "__builtins__.core.type"
1.9
1.10 predefined_constant_members = (
1.11 @@ -491,6 +492,14 @@
1.12 if data is not None:
1.13 attrs["__data__"] = data
1.14
1.15 + # Also set a key for dynamic attribute lookup, if a string.
1.16 +
1.17 + if cls == self.string_type:
1.18 + if data in self.optimiser.all_attrnames:
1.19 + attrs["__key__"] = data
1.20 + else:
1.21 + attrs["__key__"] = None
1.22 +
1.23 # Define the structure details. An object is created for the constant,
1.24 # but an attribute is provided, referring to the object, for access to
1.25 # the constant in the program.
1.26 @@ -871,6 +880,13 @@
1.27 encode_literal_constant_value(attr)))
1.28 continue
1.29
1.30 + # Special internal key member.
1.31 +
1.32 + elif attrname == "__key__":
1.33 + structure.append("{.code=%s, .pos=%s}" % (attr and encode_symbol("code", attr) or "0",
1.34 + attr and encode_symbol("pos", attr) or "0"))
1.35 + continue
1.36 +
1.37 # Special cases.
1.38
1.39 elif attrname in ("__file__", "__fname__", "__mname__", "__name__"):
2.1 --- a/lib/__builtins__/attribute.py Fri Dec 09 23:30:41 2016 +0100
2.2 +++ b/lib/__builtins__/attribute.py Fri Dec 09 23:51:47 2016 +0100
2.3 @@ -19,19 +19,11 @@
2.4 this program. If not, see <http://www.gnu.org/licenses/>.
2.5 """
2.6
2.7 +from __builtins__.types import check_string
2.8 from native import object_getattr
2.9
2.10 _default=object() # a unique placeholder for a missing value
2.11
2.12 -def _getattr(obj, name, default=_default):
2.13 -
2.14 - """
2.15 - Return for 'obj' the attribute having the given 'name', returning the given
2.16 - 'default' if the attribute is not defined for 'obj'.
2.17 - """
2.18 -
2.19 - return object_getattr(obj, name, default)
2.20 -
2.21 def getattr(obj, name, default=_default):
2.22
2.23 """
2.24 @@ -40,13 +32,27 @@
2.25 'default' is not indicated and the attribute is not defined.
2.26 """
2.27
2.28 - result = _getattr(obj, name, default)
2.29 + check_string(name)
2.30 +
2.31 + # Attempt to obtain the attribute. If the name is not recognised as an
2.32 + # attribute name, the default will be returned. Otherwise, an access
2.33 + # operation will be attempted.
2.34 +
2.35 + try:
2.36 + result = object_getattr(obj, name, default)
2.37 +
2.38 + # Handle exceptions when the access operation fails.
2.39 +
2.40 + except TypeError:
2.41 + result = _default
2.42 +
2.43 + # Check the result and, if it is the placeholder value, raise an exception.
2.44
2.45 if result is _default:
2.46 - if default is _default:
2.47 - raise AttributeError(name)
2.48 - else:
2.49 - return default
2.50 + raise AttributeError(name)
2.51 +
2.52 + # Otherwise, return the obtained value or supplied default.
2.53 +
2.54 else:
2.55 return result
2.56
2.57 @@ -54,8 +60,15 @@
2.58
2.59 "Return whether 'obj' has an attribute called 'name'."
2.60
2.61 - result = _getattr(obj, name)
2.62 - return result is not _default
2.63 + try:
2.64 + getattr(obj, name)
2.65 + except AttributeError:
2.66 + return False
2.67 + else:
2.68 + return True
2.69 +
2.70 +# NOTE: setattr would probably only be supported on instances due to deductions
2.71 +# NOTE: applying to static objects being undermined by dynamic modifications.
2.72
2.73 def setattr(obj, name, value): pass
2.74
3.1 --- a/lib/__builtins__/str.py Fri Dec 09 23:30:41 2016 +0100
3.2 +++ b/lib/__builtins__/str.py Fri Dec 09 23:51:47 2016 +0100
3.3 @@ -42,6 +42,12 @@
3.4
3.5 self.__data__ = None
3.6
3.7 + # Note the __key__ member. This is also initialised statically. Where
3.8 + # a string is the same as an attribute name, the __key__ member contains
3.9 + # attribute position and code details.
3.10 +
3.11 + self.__key__ = None
3.12 +
3.13 def __hash__(self):
3.14
3.15 "Return a value for hashing purposes."
4.1 --- a/templates/native/common.c Fri Dec 09 23:30:41 2016 +0100
4.2 +++ b/templates/native/common.c Fri Dec 09 23:51:47 2016 +0100
4.3 @@ -36,9 +36,10 @@
4.4
4.5 __attr __new_str(char *s)
4.6 {
4.7 - /* Create a new string and mutate the __data__ attribute. */
4.8 + /* Create a new string and mutate the __data__ and __key__ attributes. */
4.9 __attr attr = __new(&__InstanceTable___builtins___str_string, &__builtins___str_string, sizeof(__obj___builtins___str_string));
4.10 attr.value->attrs[__pos___data__].strvalue = s;
4.11 + attr.value->attrs[__pos___key__] = (__attr) {0, 0};
4.12 return attr;
4.13 }
4.14
5.1 --- a/templates/native/introspection.c Fri Dec 09 23:30:41 2016 +0100
5.2 +++ b/templates/native/introspection.c Fri Dec 09 23:51:47 2016 +0100
5.3 @@ -31,9 +31,13 @@
5.4 __attr * const obj = &__args[1];
5.5 __attr * const name = &__args[2];
5.6 __attr * const _default = &__args[3];
5.7 + /* name.__data__ interpreted as string */
5.8 + __attr key = __load_via_object(name->value, __pos___key__);
5.9
5.10 - /* NOTE: To be written. */
5.11 - return __builtins___none_None;
5.12 + if ((key.code == 0) && (key.pos == 0))
5.13 + return *_default;
5.14 + else
5.15 + return __check_and_load_via_any(obj->value, key.pos, key.code);
5.16 }
5.17
5.18 static int __issubclass(__ref obj, __attr cls)
6.1 --- a/templates/types.h Fri Dec 09 23:30:41 2016 +0100
6.2 +++ b/templates/types.h Fri Dec 09 23:51:47 2016 +0100
6.3 @@ -57,6 +57,7 @@
6.4 __obj * context; /* attribute context */
6.5 unsigned int min; /* minimum number of parameters */
6.6 __obj * b; /* bound callable object */
6.7 + unsigned int code; /* parameter table code for key */
6.8 };
6.9
6.10 /* One of... */
6.11 @@ -64,6 +65,7 @@
6.12 {
6.13 __obj * value; /* attribute value */
6.14 const __ptable * ptable;/* parameter table */
6.15 + unsigned int pos; /* parameter table position for key */
6.16 struct __attr (*fn)(); /* callable details */
6.17
6.18 int intvalue; /* integer value */
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/tests/getattr.py Fri Dec 09 23:51:47 2016 +0100
7.3 @@ -0,0 +1,38 @@
7.4 +class C:
7.5 + def __init__(self):
7.6 + self.x = 1
7.7 + self.y = 2
7.8 + self.z = 3
7.9 +
7.10 +class D:
7.11 + def __init__(self):
7.12 + self.x = 4
7.13 + self.y = 5
7.14 + self.z = 6
7.15 +
7.16 +c = C()
7.17 +d = D()
7.18 +
7.19 +attrnames = ["a", "b", "c", "x", "y", "z"]
7.20 +
7.21 +print ". c d"
7.22 +
7.23 +for attrname in attrnames:
7.24 + print attrname, hasattr(c, attrname) and "1" or "0", hasattr(d, attrname) and "1" or "0"
7.25 +
7.26 +print
7.27 +print ". c d"
7.28 +
7.29 +for attrname in attrnames:
7.30 + print attrname,
7.31 + try:
7.32 + v = getattr(c, attrname)
7.33 + print "", v,
7.34 + except AttributeError:
7.35 + print " ?",
7.36 +
7.37 + try:
7.38 + v = getattr(d, attrname)
7.39 + print "", v
7.40 + except AttributeError:
7.41 + print " ?"