go-python / gpython

gpython is a python interpreter written in go "batteries not included"
BSD 3-Clause "New" or "Revised" License
870 stars 95 forks source link

all: fix iterable object, implement `filter`, `map`, `oct` and optimise `hex` #222

Closed wetor closed 1 year ago

wetor commented 1 year ago

all: support filter builtin feature and fix iterable object

Python-3.4.9/Doc/c-api/iterator.rst

Python provides two general-purpose iterator objects. The first, a sequence iterator, works with an arbitrary sequence supporting the :meth:__getitem__ method. The second works with a callable object and a sentinel value, calling the callable for each item in the sequence, and ending the iteration when the sentinel value is returned.

Python-3.4.9/Lib/test/test_builtin.py

class Squares:

    def __init__(self, max):
        self.max = max
        self.sofar = []

    def __len__(self): return len(self.sofar)

    def __getitem__(self, i):
        if not 0 <= i < self.max: raise IndexError
        n = len(self.sofar)
        while n <= i:
            self.sofar.append(n*n)
            n += 1
        return self.sofar[i]

In CPython, Squares (5) is an iterable object, and to support this type of iterable object, I made modifications to Iterator. go


Iterator. go

type Iterator struct {
    Pos int
    Seq Object
}
// ...
func (it *Iterator) M__next__() (res Object, err error) {
    if tuple, ok := it.Seq.(Tuple); ok {
        if it.Pos >= len(tuple) {
            return nil, StopIteration
        }
        res = tuple[it.Pos]
        it.Pos++
        return res, nil
    }
    index := Int(it.Pos)
    if I, ok := it.Seq.(I__getitem__); ok {
        res, err = I.M__getitem__(index)
    } else if res, ok, err = TypeCall1(it.Seq, "__getitem__", index); !ok {
        return nil, ExceptionNewf(TypeError, "'%s' object is not iterable", it.Type().Name)
    }
    if err != nil {
        if IsException(IndexError, err) {
            return nil, StopIteration
        }
        return nil, err
    }
    it.Pos++
    return res, nil
}

Corresponding CPython code
Python-3.4.9/Objects/iterobject.c

static PyObject *
iter_iternext(PyObject *iterator)
{
    seqiterobject *it;
    PyObject *seq;
    PyObject *result;

    assert(PySeqIter_Check(iterator));
    it = (seqiterobject *)iterator;
    seq = it->it_seq;
    if (seq == NULL)
        return NULL;
    if (it->it_index == PY_SSIZE_T_MAX) {
        PyErr_SetString(PyExc_OverflowError,
                        "iter index too large");
        return NULL;
    }

    result = PySequence_GetItem(seq, it->it_index);
    if (result != NULL) {
        it->it_index++;
        return result;
    }
    if (PyErr_ExceptionMatches(PyExc_IndexError) ||
        PyErr_ExceptionMatches(PyExc_StopIteration))
    {
        PyErr_Clear();
        Py_DECREF(seq);
        it->it_seq = NULL;
    }
    return NULL;
}

and Iter()

func Iter(self Object) (res Object, err error) {
    if I, ok := self.(I__iter__); ok {
        return I.M__iter__()
    } else if res, ok, err = TypeCall0(self, "__iter__"); ok {
        return res, err
    }
    if ObjectIsSequence(self) {
        return NewIterator(self), nil
    }
    return nil, ExceptionNewf(TypeError, "'%s' object is not iterable", self.Type().Name)
}

Corresponding CPython code
Python-3.4.9/Objects/abstract.c

PyObject *
PyObject_GetIter(PyObject *o)
{
    PyTypeObject *t = o->ob_type;
    getiterfunc f = NULL;
    f = t->tp_iter;
    if (f == NULL) {
        if (PySequence_Check(o))
            return PySeqIter_New(o);
        return type_error("'%.200s' object is not iterable", o);
    }
    else {
        PyObject *res = (*f)(o);
        if (res != NULL && !PyIter_Check(res)) {
            PyErr_Format(PyExc_TypeError,
                         "iter() returned non-iterator "
                         "of type '%.100s'",
                         res->ob_type->tp_name);
            Py_DECREF(res);
            res = NULL;
        }
        return res;
    }
}

Finally, filter and map methods were fully implemented

py/tests/filter.py is a copy of Python-3.4.9/Lib/test/test_builtin.py:BuiltinTest.test_filter() and py/tests/map.py is a copy of Python-3.4.9/Lib/test/test_builtin.py:BuiltinTest.test_map()

builtin: Implement oct and optimise hex

Through benchmark testing, the speed of hex has indeed been improved

My English is not very good, so forgive me for not providing sufficient explanations. Welcome to ask questions here

codecov[bot] commented 1 year ago

Codecov Report

Patch coverage: 83.13% and project coverage change: +0.10 :tada:

Comparison is base (acd458b) 74.42% compared to head (04a9c5b) 74.52%.

Additional details and impacted files ```diff @@ Coverage Diff @@ ## main #222 +/- ## ========================================== + Coverage 74.42% 74.52% +0.10% ========================================== Files 76 78 +2 Lines 12675 12804 +129 ========================================== + Hits 9433 9542 +109 - Misses 2567 2583 +16 - Partials 675 679 +4 ``` | [Impacted Files](https://app.codecov.io/gh/go-python/gpython/pull/222?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-python) | Coverage Δ | | |---|---|---| | [py/arithmetic.go](https://app.codecov.io/gh/go-python/gpython/pull/222?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-python#diff-cHkvYXJpdGhtZXRpYy5nbw==) | `61.04% <ø> (-0.18%)` | :arrow_down: | | [py/list.go](https://app.codecov.io/gh/go-python/gpython/pull/222?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-python#diff-cHkvbGlzdC5nbw==) | `64.16% <60.00%> (+0.03%)` | :arrow_up: | | [stdlib/builtin/builtin.go](https://app.codecov.io/gh/go-python/gpython/pull/222?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-python#diff-c3RkbGliL2J1aWx0aW4vYnVpbHRpbi5nbw==) | `78.21% <63.79%> (-1.86%)` | :arrow_down: | | [py/iterator.go](https://app.codecov.io/gh/go-python/gpython/pull/222?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-python#diff-cHkvaXRlcmF0b3IuZ28=) | `86.95% <88.88%> (-3.96%)` | :arrow_down: | | [py/filter.go](https://app.codecov.io/gh/go-python/gpython/pull/222?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-python#diff-cHkvZmlsdGVyLmdv) | `92.59% <92.59%> (ø)` | | | [py/object.go](https://app.codecov.io/gh/go-python/gpython/pull/222?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-python#diff-cHkvb2JqZWN0Lmdv) | `89.18% <93.93%> (+22.52%)` | :arrow_up: | | [py/dict.go](https://app.codecov.io/gh/go-python/gpython/pull/222?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-python#diff-cHkvZGljdC5nbw==) | `82.01% <100.00%> (ø)` | | | [py/exception.go](https://app.codecov.io/gh/go-python/gpython/pull/222?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-python#diff-cHkvZXhjZXB0aW9uLmdv) | `64.00% <100.00%> (+3.79%)` | :arrow_up: | | [py/internal.go](https://app.codecov.io/gh/go-python/gpython/pull/222?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-python#diff-cHkvaW50ZXJuYWwuZ28=) | `57.14% <100.00%> (+1.58%)` | :arrow_up: | | [py/map.go](https://app.codecov.io/gh/go-python/gpython/pull/222?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-python#diff-cHkvbWFwLmdv) | `100.00% <100.00%> (ø)` | | | ... and [1 more](https://app.codecov.io/gh/go-python/gpython/pull/222?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-python) | | ... and [1 file with indirect coverage changes](https://app.codecov.io/gh/go-python/gpython/pull/222/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=go-python)

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Do you have feedback about the report comment? Let us know in this issue.

wetor commented 1 year ago

Of course, I will split commit later

wetor commented 1 year ago

I found that the basic types (int, string, etc.) did not run Ready() correctly, resulting some attribute was not registered correctly and was fixed by the way https://github.com/go-python/gpython/pull/222/commits/b4b7ef221456e742947a8e369bd8892828e75485