From 5558a8b77143247a1942da2e3ce333ec0aa1fde0 Mon Sep 17 00:00:00 2001 From: Jack Park Date: Sun, 20 Oct 2019 19:40:08 +0700 Subject: [PATCH] Implemented isinstance --- builtin/builtin.go | 41 ++++++++++++++++++++++++++++++++++++++++- vm/tests/builtin.py | 10 ++++++++++ vm/tests/libtest.py | 17 +++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 vm/tests/libtest.py diff --git a/builtin/builtin.go b/builtin/builtin.go index b009090a..145da84c 100644 --- a/builtin/builtin.go +++ b/builtin/builtin.go @@ -44,7 +44,7 @@ func init() { // py.MustNewMethod("hex", builtin_hex, 0, hex_doc), // py.MustNewMethod("id", builtin_id, 0, id_doc), // py.MustNewMethod("input", builtin_input, 0, input_doc), - // py.MustNewMethod("isinstance", builtin_isinstance, 0, isinstance_doc), + py.MustNewMethod("isinstance", builtin_isinstance, 0, isinstance_doc), // py.MustNewMethod("issubclass", builtin_issubclass, 0, issubclass_doc), py.MustNewMethod("iter", builtin_iter, 0, iter_doc), py.MustNewMethod("len", builtin_len, 0, len_doc), @@ -826,6 +826,45 @@ object. The globals and locals are dictionaries, defaulting to the current globals and locals. If only globals is given, locals defaults to it.` +const isinstance_doc = `isinstance(obj, class_or_tuple) -> bool + +Return whether an object is an instance of a class or of a subclass thereof. + +A tuple, as in isinstance(x, (A, B, ...)), may be given as the target to +check against. This is equivalent to isinstance(x, A) or isinstance(x, B) +or ... etc. +` + +func isinstance(obj py.Object, classOrTuple py.Object) (py.Bool, error) { + switch classOrTuple.(type) { + case py.Tuple: + var class_tuple = classOrTuple.(py.Tuple) + for idx := range class_tuple { + res, _ := isinstance(obj, class_tuple[idx]) + if res { + return res, nil + } + } + return false, nil + default: + if classOrTuple.Type().ObjectType != py.TypeType { + return false, py.ExceptionNewf(py.TypeError, "isinstance() arg 2 must be a type or tuple of types") + } + return obj.Type() == classOrTuple, nil + } +} + +func builtin_isinstance(self py.Object, args py.Tuple) (py.Object, error) { + var obj py.Object + var classOrTuple py.Object + err := py.UnpackTuple(args, nil, "isinstance", 2, 2, &obj, &classOrTuple) + if err != nil { + return nil, err + } + + return isinstance(obj, classOrTuple) +} + const iter_doc = `iter(iterable) -> iterator iter(callable, sentinel) -> iterator diff --git a/vm/tests/builtin.py b/vm/tests/builtin.py index c50e1dd3..94f2e3a7 100644 --- a/vm/tests/builtin.py +++ b/vm/tests/builtin.py @@ -1,6 +1,7 @@ # Copyright 2018 The go-python Authors. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. +from libtest import assertRaises doc="eval" assert eval("1+2") == 3 @@ -65,4 +66,13 @@ else: assert False, "SyntaxError not raised" +doc="isinstance" +class A: + pass +a = A() +assert True, isinstance(1, (str, tuple, int)) +assert True, isinstance(a, (str, (tuple, (A, )))) +assertRaises(TypeError, isinstance, 1, (A, ), "foo") +assertRaises(TypeError, isinstance, 1, [A, "foo"]) + doc="finished" diff --git a/vm/tests/libtest.py b/vm/tests/libtest.py new file mode 100644 index 00000000..feebd7ee --- /dev/null +++ b/vm/tests/libtest.py @@ -0,0 +1,17 @@ +# Copyright 2018 The go-python Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +""" +Simple test harness +""" + +def assertRaises(expecting, fn, *args, **kwargs): + """Check the exception was raised - don't check the text""" + try: + fn(*args, **kwargs) + except expecting as e: + pass + else: + assert False, "%s not raised" % (expecting,) +