# HG changeset patch # User Paul Boddie # Date 1480010110 -3600 # Node ID 72b93c7c757aeaa4b5e7a7e18d2fe3ec5ffc13f6 # Parent c21393bbe00228a8b8ddc787081b0070bfd38eab Added issubclass and improved isinstance, also introducing various native functions and operations. diff -r c21393bbe002 -r 72b93c7c757a lib/__builtins__/identity.py --- a/lib/__builtins__/identity.py Thu Nov 24 00:58:36 2016 +0100 +++ b/lib/__builtins__/identity.py Thu Nov 24 18:55:10 2016 +0100 @@ -19,31 +19,68 @@ this program. If not, see . """ -from native import _isinstance +from native import _isinstance, _issubclass + +def callable(obj): + + "Return whether 'obj' is callable." + + # NOTE: Classes and functions are callable, modules are not callable, + # NOTE: only instances with __call__ methods should be callable. + + pass + +def help(*args): + + # NOTE: This should show any docstring, but it is currently unsupported. -def callable(obj): pass -def help(*args): pass -def id(obj): pass + pass + +def id(obj): + + # NOTE: This should show an object's address, but it is currently + # NOTE: unsupported. + + pass + +def isclass(obj): + + "Return whether 'obj' is a class." + + return obj.__class__ is type def isinstance(obj, cls_or_tuple): """ Return whether 'obj' is an instance of 'cls_or_tuple', where the latter is - either a class or a tuple of classes. + either a class or a sequence of classes. """ - # NOTE: CPython insists on tuples, but any sequence might be considered - # NOTE: acceptable. - if _isinstance(cls_or_tuple, tuple): for cls in cls_or_tuple: - if obj.__class__ is cls or _isinstance(obj, cls): + if obj.__class__ is cls or isclass(cls) and _isinstance(obj, cls): return True return False else: - return obj.__class__ is cls_or_tuple or _isinstance(obj, cls_or_tuple) + return obj.__class__ is cls_or_tuple or isclass(cls_or_tuple) and _isinstance(obj, cls_or_tuple) + +def issubclass(obj, cls_or_tuple): + + """ + Return whether 'obj' is a class that is a subclass of 'cls_or_tuple', where + the latter is either a class or a sequence of classes. If 'obj' is the same + as the given class or classes, True is also returned. + """ -def issubclass(obj, cls_or_tuple): pass + if not isclass(obj): + return False + elif _isinstance(cls_or_tuple, tuple): + for cls in cls_or_tuple: + if obj is cls or isclass(cls) and _issubclass(obj, cls): + return True + return False + else: + return obj is cls_or_tuple or isclass(cls_or_tuple) and _issubclass(obj, cls_or_tuple) def repr(obj): diff -r c21393bbe002 -r 72b93c7c757a lib/native.py --- a/lib/native.py Thu Nov 24 00:58:36 2016 +0100 +++ b/lib/native.py Thu Nov 24 18:55:10 2016 +0100 @@ -68,6 +68,7 @@ def _object_getattr(obj, name, default): pass def _isinstance(obj, cls): pass +def _issubclass(obj, cls): pass def _read(fd, n): pass def _write(fd, str): pass diff -r c21393bbe002 -r 72b93c7c757a templates/native.c --- a/templates/native.c Thu Nov 24 00:58:36 2016 +0100 +++ b/templates/native.c Thu Nov 24 18:55:10 2016 +0100 @@ -13,7 +13,7 @@ /* Utility functions. */ -inline __attr __new_int(int i) +static __attr __new_int(int i) { /* Create a new integer and mutate the __data__ attribute. */ __attr attr = __new(&__InstanceTable___builtins___int_int, &__builtins___int_int, sizeof(__obj___builtins___int_int)); @@ -21,7 +21,7 @@ return attr; } -inline __attr __new_str(char *s) +static __attr __new_str(char *s) { /* Create a new string and mutate the __data__ attribute. */ __attr attr = __new(&__InstanceTable___builtins___str_string, &__builtins___str_string, sizeof(__obj___builtins___str_string)); @@ -512,12 +512,30 @@ return __builtins___none_None; } +static int __issubclass(__ref obj, __attr cls) +{ + return (__HASATTR(obj, __TYPEPOS(cls.value), __TYPECODE(cls.value))); +} + __attr __fn_native__isinstance(__attr __args[]) { __attr * const obj = &__args[1]; __attr * const cls = &__args[2]; - if (__is_instance(obj->value) && __HASATTR(__get_class(obj->value), __TYPEPOS(cls->value), __TYPECODE(cls->value))) + /* cls must be a class. */ + if (__is_instance(obj->value) && __issubclass(__get_class(obj->value), *cls)) + return __builtins___boolean_True; + else + return __builtins___boolean_False; +} + +__attr __fn_native__issubclass(__attr __args[]) +{ + __attr * const obj = &__args[1]; + __attr * const cls = &__args[2]; + + /* obj and cls must be classes. */ + if (__issubclass(obj->value, *cls)) return __builtins___boolean_True; else return __builtins___boolean_False; diff -r c21393bbe002 -r 72b93c7c757a templates/native.h --- a/templates/native.h Thu Nov 24 00:58:36 2016 +0100 +++ b/templates/native.h Thu Nov 24 18:55:10 2016 +0100 @@ -57,6 +57,7 @@ __attr __fn_native__object_getattr(__attr __args[]); __attr __fn_native__isinstance(__attr __args[]); +__attr __fn_native__issubclass(__attr __args[]); __attr __fn_native__read(__attr __args[]); __attr __fn_native__write(__attr __args[]); diff -r c21393bbe002 -r 72b93c7c757a templates/ops.c --- a/templates/ops.c Thu Nov 24 00:58:36 2016 +0100 +++ b/templates/ops.c Thu Nov 24 18:55:10 2016 +0100 @@ -53,6 +53,11 @@ return __load_via_object(obj, __pos___class__).value; } +__attr __get_class_attr(__ref obj) +{ + return __load_via_object(obj, __pos___class__); +} + /* Attribute testing operations. */ __ref __test_specific_instance(__ref obj, __ref type) diff -r c21393bbe002 -r 72b93c7c757a templates/ops.h --- a/templates/ops.h Thu Nov 24 00:58:36 2016 +0100 +++ b/templates/ops.h Thu Nov 24 18:55:10 2016 +0100 @@ -24,6 +24,7 @@ int __is_instance(__ref obj); __ref __get_class(__ref obj); +__attr __get_class_attr(__ref obj); /* Attribute testing operations. */ diff -r c21393bbe002 -r 72b93c7c757a tests/identity.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/identity.py Thu Nov 24 18:55:10 2016 +0100 @@ -0,0 +1,58 @@ +print isinstance("string", string) # True +print isinstance("string", int) # False +print isinstance(123, int) # True +print isinstance(123, string) # False +print + +class A: + pass + +class B(A): + pass + +class C(B): + pass + +a = A() +b = B() +c = C() + +print isinstance(a, A) # True +print isinstance(b, B) # True +print isinstance(c, C) # True +print +print isinstance(a, a) # False +print isinstance(b, b) # False +print isinstance(c, c) # False +print +print isinstance(A, a) # False +print isinstance(B, b) # False +print isinstance(C, c) # False +print +print isinstance(a, B) # False +print isinstance(b, C) # False +print isinstance(c, A) # True +print +print isinstance(a, C) # False +print isinstance(b, A) # True +print isinstance(c, B) # True +print +print issubclass(A, A) # True +print issubclass(B, B) # True +print issubclass(C, C) # True +print +print issubclass(a, a) # False +print issubclass(b, b) # False +print issubclass(c, c) # False +print +print issubclass(a, A) # False +print issubclass(b, B) # False +print issubclass(c, C) # False +print +print issubclass(A, B) # False +print issubclass(B, C) # False +print issubclass(C, A) # True +print +print issubclass(A, C) # False +print issubclass(B, A) # True +print issubclass(C, B) # True