mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
use cpython style next()
This commit is contained in:
parent
508cbfdb75
commit
6189aaca94
@ -30,40 +30,13 @@ The easiest way to test a feature is to [try it on your browser](https://pocketp
|
|||||||
## Different behaviors
|
## Different behaviors
|
||||||
|
|
||||||
1. positional and keyword arguments are strictly evaluated.
|
1. positional and keyword arguments are strictly evaluated.
|
||||||
2. When a generator is exhausted, `StopIteration` is returned instead of raised.
|
2. `++i` and `--j` is an increment/decrement statement, not an expression.
|
||||||
3. `++i` and `--j` is an increment/decrement statement, not an expression.
|
3. `int` does not derive from `bool`.
|
||||||
4. `int` does not derive from `bool`.
|
4. `int` is 64-bit. You can use `long` type explicitly for arbitrary sized integers.
|
||||||
5. `int` is 64-bit. You can use `long` type explicitly for arbitrary sized integers.
|
5. `__ne__` is not required. Define `__eq__` is enough.
|
||||||
6. `__ne__` is not required. Define `__eq__` is enough.
|
6. Raw string cannot have boundary quotes in it, even escaped. See [#55](https://github.com/pocketpy/pocketpy/issues/55).
|
||||||
7. Raw string cannot have boundary quotes in it, even escaped. See [#55](https://github.com/pocketpy/pocketpy/issues/55).
|
7. In a starred unpacked assignment, e.g. `a, b, *c = x`, the starred variable can only be presented in the last position. `a, *b, c = x` is not supported.
|
||||||
8. In a starred unpacked assignment, e.g. `a, b, *c = x`, the starred variable can only be presented in the last position. `a, *b, c = x` is not supported.
|
8. A `Tab` is equivalent to 4 spaces. You can mix `Tab` and spaces in indentation, but it is not recommended.
|
||||||
9. A `Tab` is equivalent to 4 spaces. You can mix `Tab` and spaces in indentation, but it is not recommended.
|
9. `%`, `&`, `//`, `^` and `|` for `int` behave the same as C, not python.
|
||||||
10. `%`, `&`, `//`, `^` and `|` for `int` behave the same as C, not python.
|
10. `str.split` and `str.splitlines` will remove all empty entries.
|
||||||
11. `str.split` and `str.splitlines` will remove all empty entries.
|
11. `__getattr__`, `__setattr__` and `__delattr__` can only be set in cpp.
|
||||||
12. `__getattr__`, `__setattr__` and `__delattr__` can only be set in cpp.
|
|
||||||
|
|
||||||
### Make `next()` compatible with cpython
|
|
||||||
|
|
||||||
You can use the following code to make `next()` compatible with cpython temporarily.
|
|
||||||
|
|
||||||
```python
|
|
||||||
import builtins
|
|
||||||
|
|
||||||
def next(obj):
|
|
||||||
res = builtins.next(obj)
|
|
||||||
if res is StopIteration:
|
|
||||||
raise StopIteration
|
|
||||||
return res
|
|
||||||
|
|
||||||
a = iter([1])
|
|
||||||
assert next(a) == 1
|
|
||||||
|
|
||||||
try:
|
|
||||||
next(a)
|
|
||||||
except StopIteration:
|
|
||||||
print("a is exhausted")
|
|
||||||
```
|
|
||||||
|
|
||||||
!!!
|
|
||||||
Do not change `builtins.next`. It will break internal functions which rely on `StopIteration` as return value.
|
|
||||||
!!!
|
|
||||||
|
@ -11,7 +11,7 @@ pkpy is licensed under the [MIT License](http://opensource.org/licenses/MIT).
|
|||||||
```
|
```
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2023 blueloveTH
|
Copyright (c) 2024 blueloveTH
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -14,5 +14,6 @@ void add_module_dis(VM* vm);
|
|||||||
void add_module_gc(VM* vm);
|
void add_module_gc(VM* vm);
|
||||||
void add_module_line_profiler(VM* vm);
|
void add_module_line_profiler(VM* vm);
|
||||||
void add_module_enum(VM* vm);
|
void add_module_enum(VM* vm);
|
||||||
|
void add_module___builtins(VM* vm);
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
7
include/typings/__builtins.pyi
Normal file
7
include/typings/__builtins.pyi
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from typing import Any
|
||||||
|
|
||||||
|
def next(iter) -> Any | StopIteration:
|
||||||
|
...
|
||||||
|
|
||||||
|
def _enable_instance_dict(obj) -> None:
|
||||||
|
...
|
5
pyrightconfig.json
Normal file
5
pyrightconfig.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"stubPath": "include/typings",
|
||||||
|
"reportMissingModuleSource": "none",
|
||||||
|
"pythonVersion": "3.10"
|
||||||
|
}
|
@ -1,36 +1,36 @@
|
|||||||
import sys as _sys
|
from operator import lt as __operator_lt
|
||||||
import operator as _operator
|
from operator import gt as __operator_gt
|
||||||
|
from __builtins import next as __builtins_next
|
||||||
|
|
||||||
def print(*args, sep=' ', end='\n'):
|
def __minmax_reduce(op, args, key):
|
||||||
s = sep.join([str(i) for i in args])
|
|
||||||
_sys.stdout.write(s + end)
|
|
||||||
|
|
||||||
def _minmax_reduce(op, args, key):
|
|
||||||
if key is None:
|
if key is None:
|
||||||
if len(args) == 2:
|
if len(args) == 2:
|
||||||
return args[0] if op(args[0], args[1]) else args[1]
|
return args[0] if op(args[0], args[1]) else args[1]
|
||||||
key = lambda x: x
|
|
||||||
if len(args) == 0:
|
if len(args) == 0:
|
||||||
raise TypeError('expected 1 arguments, got 0')
|
raise TypeError('expected 1 arguments, got 0')
|
||||||
if len(args) == 1:
|
if len(args) == 1:
|
||||||
args = args[0]
|
args = args[0]
|
||||||
args = iter(args)
|
args = iter(args)
|
||||||
res = next(args)
|
res = __builtins_next(args)
|
||||||
if res is StopIteration:
|
if res is StopIteration:
|
||||||
raise ValueError('args is an empty sequence')
|
raise ValueError('args is an empty sequence')
|
||||||
while True:
|
while True:
|
||||||
i = next(args)
|
i = __builtins_next(args)
|
||||||
if i is StopIteration:
|
if i is StopIteration:
|
||||||
break
|
break
|
||||||
|
if key is None:
|
||||||
|
if op(i, res):
|
||||||
|
res = i
|
||||||
|
else:
|
||||||
if op(key(i), key(res)):
|
if op(key(i), key(res)):
|
||||||
res = i
|
res = i
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def min(*args, key=None):
|
def min(*args, key=None):
|
||||||
return _minmax_reduce(_operator.lt, args, key)
|
return __minmax_reduce(__operator_lt, args, key)
|
||||||
|
|
||||||
def max(*args, key=None):
|
def max(*args, key=None):
|
||||||
return _minmax_reduce(_operator.gt, args, key)
|
return __minmax_reduce(__operator_gt, args, key)
|
||||||
|
|
||||||
def all(iterable):
|
def all(iterable):
|
||||||
for i in iterable:
|
for i in iterable:
|
||||||
@ -69,8 +69,8 @@ def zip(a, b):
|
|||||||
a = iter(a)
|
a = iter(a)
|
||||||
b = iter(b)
|
b = iter(b)
|
||||||
while True:
|
while True:
|
||||||
ai = next(a)
|
ai = __builtins_next(a)
|
||||||
bi = next(b)
|
bi = __builtins_next(b)
|
||||||
if ai is StopIteration or bi is StopIteration:
|
if ai is StopIteration or bi is StopIteration:
|
||||||
break
|
break
|
||||||
yield ai, bi
|
yield ai, bi
|
||||||
|
@ -7,10 +7,12 @@ def Counter(iterable):
|
|||||||
a[x] = 1
|
a[x] = 1
|
||||||
return a
|
return a
|
||||||
|
|
||||||
|
from __builtins import _enable_instance_dict
|
||||||
|
|
||||||
class defaultdict(dict):
|
class defaultdict(dict):
|
||||||
def __init__(self, default_factory, *args):
|
def __init__(self, default_factory, *args):
|
||||||
super().__init__(*args)
|
super().__init__(*args)
|
||||||
self._enable_instance_dict()
|
_enable_instance_dict(self)
|
||||||
self.default_factory = default_factory
|
self.default_factory = default_factory
|
||||||
|
|
||||||
def __missing__(self, key):
|
def __missing__(self, key):
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from __builtins import next
|
||||||
|
|
||||||
class cache:
|
class cache:
|
||||||
def __init__(self, f):
|
def __init__(self, f):
|
||||||
self.f = f
|
self.f = f
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from __builtins import next
|
||||||
|
|
||||||
def zip_longest(a, b):
|
def zip_longest(a, b):
|
||||||
a = iter(a)
|
a = iter(a)
|
||||||
b = iter(b)
|
b = iter(b)
|
||||||
|
File diff suppressed because one or more lines are too long
@ -337,4 +337,20 @@ void add_module_enum(VM* vm){
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add_module___builtins(VM* vm){
|
||||||
|
PyObject* mod = vm->new_module("__builtins");
|
||||||
|
|
||||||
|
vm->bind_func<1>(mod, "next", [](VM* vm, ArgsView args){
|
||||||
|
return vm->py_next(args[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
vm->bind_func<1>(mod, "_enable_instance_dict", [](VM* vm, ArgsView args){
|
||||||
|
PyObject* self = args[0];
|
||||||
|
if(is_tagged(self)) vm->TypeError("object: tagged object cannot enable instance dict");
|
||||||
|
if(self->is_attr_valid()) vm->RuntimeError("object: instance dict is already enabled");
|
||||||
|
self->_enable_instance_dict();
|
||||||
|
return vm->None;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
@ -297,7 +297,9 @@ void init_builtins(VM* _vm) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_func<1>(_vm->builtins, "next", [](VM* vm, ArgsView args) {
|
_vm->bind_func<1>(_vm->builtins, "next", [](VM* vm, ArgsView args) {
|
||||||
return vm->py_next(args[0]);
|
PyObject* retval = vm->py_next(args[0]);
|
||||||
|
if(retval == vm->StopIteration) vm->_error(vm->call(vm->StopIteration));
|
||||||
|
return retval;
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_func<1>(_vm->builtins, "bin", [](VM* vm, ArgsView args) {
|
_vm->bind_func<1>(_vm->builtins, "bin", [](VM* vm, ArgsView args) {
|
||||||
@ -350,18 +352,6 @@ void init_builtins(VM* _vm) {
|
|||||||
return vm->heap.gcnew<DummyInstance>(t);
|
return vm->heap.gcnew<DummyInstance>(t);
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_method<0>(VM::tp_object, "_enable_instance_dict", [](VM* vm, ArgsView args){
|
|
||||||
PyObject* self = args[0];
|
|
||||||
if(is_tagged(self)){
|
|
||||||
vm->TypeError("object: tagged object cannot enable instance dict");
|
|
||||||
}
|
|
||||||
if(self->is_attr_valid()){
|
|
||||||
vm->TypeError("object: instance dict is already enabled");
|
|
||||||
}
|
|
||||||
self->_enable_instance_dict();
|
|
||||||
return vm->None;
|
|
||||||
});
|
|
||||||
|
|
||||||
// tp_type
|
// tp_type
|
||||||
_vm->bind_constructor<2>(_vm->_t(VM::tp_type), PK_LAMBDA(vm->_t(args[1])));
|
_vm->bind_constructor<2>(_vm->_t(VM::tp_type), PK_LAMBDA(vm->_t(args[1])));
|
||||||
|
|
||||||
@ -1588,6 +1578,21 @@ void VM::post_init(){
|
|||||||
return VAR(MappingProxy(args[0]));
|
return VAR(MappingProxy(args[0]));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
bind(builtins, "print(*args, sep=' ', end='\\n')", [](VM* vm, ArgsView args) {
|
||||||
|
const Tuple& _0 = CAST(Tuple&, args[0]);
|
||||||
|
const Str& _1 = CAST(Str&, args[1]);
|
||||||
|
const Str& _2 = CAST(Str&, args[2]);
|
||||||
|
SStream ss;
|
||||||
|
for(int i=0; i<_0.size(); i++){
|
||||||
|
ss << CAST(Str&, vm->py_str(_0[i]));
|
||||||
|
if(i != _0.size()-1) ss << _1;
|
||||||
|
}
|
||||||
|
ss << _2;
|
||||||
|
vm->stdout_write(ss.str());
|
||||||
|
return vm->None;
|
||||||
|
});
|
||||||
|
|
||||||
|
add_module___builtins(vm);
|
||||||
add_module_sys(this);
|
add_module_sys(this);
|
||||||
add_module_traceback(this);
|
add_module_traceback(this);
|
||||||
add_module_time(this);
|
add_module_time(this);
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from __builtins import next
|
||||||
|
|
||||||
a = [1, 2, 3]
|
a = [1, 2, 3]
|
||||||
a = iter(a)
|
a = iter(a)
|
||||||
|
|
||||||
@ -37,13 +39,8 @@ assert next(i) == 5
|
|||||||
assert next(i) == StopIteration
|
assert next(i) == StopIteration
|
||||||
assert next(i) == StopIteration
|
assert next(i) == StopIteration
|
||||||
|
|
||||||
import builtins
|
# test normal next
|
||||||
|
from builtins import next
|
||||||
def next(obj):
|
|
||||||
res = builtins.next(obj)
|
|
||||||
if res is StopIteration:
|
|
||||||
raise StopIteration
|
|
||||||
return res
|
|
||||||
|
|
||||||
a = iter([1])
|
a = iter([1])
|
||||||
assert next(a) == 1
|
assert next(a) == 1
|
||||||
|
@ -64,7 +64,11 @@ try:
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
assert next(t) == StopIteration
|
try:
|
||||||
|
next(t)
|
||||||
|
exit(1)
|
||||||
|
except StopIteration:
|
||||||
|
pass
|
||||||
|
|
||||||
def f():
|
def f():
|
||||||
yield 1
|
yield 1
|
||||||
|
Loading…
x
Reference in New Issue
Block a user