mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-19 19:10:17 +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
|
||||
|
||||
1. positional and keyword arguments are strictly evaluated.
|
||||
2. When a generator is exhausted, `StopIteration` is returned instead of raised.
|
||||
3. `++i` and `--j` is an increment/decrement statement, not an expression.
|
||||
4. `int` does not derive from `bool`.
|
||||
5. `int` is 64-bit. You can use `long` type explicitly for arbitrary sized integers.
|
||||
6. `__ne__` is not required. Define `__eq__` is enough.
|
||||
7. Raw string cannot have boundary quotes in it, even escaped. See [#55](https://github.com/pocketpy/pocketpy/issues/55).
|
||||
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.
|
||||
9. A `Tab` is equivalent to 4 spaces. You can mix `Tab` and spaces in indentation, but it is not recommended.
|
||||
10. `%`, `&`, `//`, `^` and `|` for `int` behave the same as C, not python.
|
||||
11. `str.split` and `str.splitlines` will remove all empty entries.
|
||||
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.
|
||||
!!!
|
||||
2. `++i` and `--j` is an increment/decrement statement, not an expression.
|
||||
3. `int` does not derive from `bool`.
|
||||
4. `int` is 64-bit. You can use `long` type explicitly for arbitrary sized integers.
|
||||
5. `__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. 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. `%`, `&`, `//`, `^` and `|` for `int` behave the same as C, not python.
|
||||
10. `str.split` and `str.splitlines` will remove all empty entries.
|
||||
11. `__getattr__`, `__setattr__` and `__delattr__` can only be set in cpp.
|
||||
|
@ -11,7 +11,7 @@ pkpy is licensed under the [MIT License](http://opensource.org/licenses/MIT).
|
||||
```
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 blueloveTH
|
||||
Copyright (c) 2024 blueloveTH
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
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_line_profiler(VM* vm);
|
||||
void add_module_enum(VM* vm);
|
||||
void add_module___builtins(VM* vm);
|
||||
|
||||
} // 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
|
||||
import operator as _operator
|
||||
from operator import lt as __operator_lt
|
||||
from operator import gt as __operator_gt
|
||||
from __builtins import next as __builtins_next
|
||||
|
||||
def print(*args, sep=' ', end='\n'):
|
||||
s = sep.join([str(i) for i in args])
|
||||
_sys.stdout.write(s + end)
|
||||
|
||||
def _minmax_reduce(op, args, key):
|
||||
if key is None:
|
||||
def __minmax_reduce(op, args, key):
|
||||
if key is None:
|
||||
if len(args) == 2:
|
||||
return args[0] if op(args[0], args[1]) else args[1]
|
||||
key = lambda x: x
|
||||
if len(args) == 0:
|
||||
raise TypeError('expected 1 arguments, got 0')
|
||||
if len(args) == 1:
|
||||
args = args[0]
|
||||
args = iter(args)
|
||||
res = next(args)
|
||||
res = __builtins_next(args)
|
||||
if res is StopIteration:
|
||||
raise ValueError('args is an empty sequence')
|
||||
while True:
|
||||
i = next(args)
|
||||
i = __builtins_next(args)
|
||||
if i is StopIteration:
|
||||
break
|
||||
if op(key(i), key(res)):
|
||||
res = i
|
||||
if key is None:
|
||||
if op(i, res):
|
||||
res = i
|
||||
else:
|
||||
if op(key(i), key(res)):
|
||||
res = i
|
||||
return res
|
||||
|
||||
def min(*args, key=None):
|
||||
return _minmax_reduce(_operator.lt, args, key)
|
||||
return __minmax_reduce(__operator_lt, args, key)
|
||||
|
||||
def max(*args, key=None):
|
||||
return _minmax_reduce(_operator.gt, args, key)
|
||||
return __minmax_reduce(__operator_gt, args, key)
|
||||
|
||||
def all(iterable):
|
||||
for i in iterable:
|
||||
@ -69,8 +69,8 @@ def zip(a, b):
|
||||
a = iter(a)
|
||||
b = iter(b)
|
||||
while True:
|
||||
ai = next(a)
|
||||
bi = next(b)
|
||||
ai = __builtins_next(a)
|
||||
bi = __builtins_next(b)
|
||||
if ai is StopIteration or bi is StopIteration:
|
||||
break
|
||||
yield ai, bi
|
||||
|
@ -7,10 +7,12 @@ def Counter(iterable):
|
||||
a[x] = 1
|
||||
return a
|
||||
|
||||
from __builtins import _enable_instance_dict
|
||||
|
||||
class defaultdict(dict):
|
||||
def __init__(self, default_factory, *args):
|
||||
super().__init__(*args)
|
||||
self._enable_instance_dict()
|
||||
_enable_instance_dict(self)
|
||||
self.default_factory = default_factory
|
||||
|
||||
def __missing__(self, key):
|
||||
|
@ -1,3 +1,5 @@
|
||||
from __builtins import next
|
||||
|
||||
class cache:
|
||||
def __init__(self, f):
|
||||
self.f = f
|
||||
|
@ -1,3 +1,5 @@
|
||||
from __builtins import next
|
||||
|
||||
def zip_longest(a, b):
|
||||
a = iter(a)
|
||||
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
|
@ -297,7 +297,9 @@ void init_builtins(VM* _vm) {
|
||||
});
|
||||
|
||||
_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) {
|
||||
@ -350,18 +352,6 @@ void init_builtins(VM* _vm) {
|
||||
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
|
||||
_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]));
|
||||
});
|
||||
|
||||
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_traceback(this);
|
||||
add_module_time(this);
|
||||
@ -1599,7 +1604,7 @@ void VM::post_init(){
|
||||
add_module_random(this);
|
||||
add_module_base64(this);
|
||||
add_module_operator(this);
|
||||
|
||||
|
||||
_lazy_modules["this"] = kPythonLibs_this;
|
||||
_lazy_modules["functools"] = kPythonLibs_functools;
|
||||
_lazy_modules["heapq"] = kPythonLibs_heapq;
|
||||
|
@ -1,3 +1,5 @@
|
||||
from __builtins import next
|
||||
|
||||
a = [1, 2, 3]
|
||||
a = iter(a)
|
||||
|
||||
@ -37,14 +39,9 @@ assert next(i) == 5
|
||||
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])
|
||||
assert next(a) == 1
|
||||
|
||||
|
@ -64,7 +64,11 @@ try:
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
assert next(t) == StopIteration
|
||||
try:
|
||||
next(t)
|
||||
exit(1)
|
||||
except StopIteration:
|
||||
pass
|
||||
|
||||
def f():
|
||||
yield 1
|
||||
|
Loading…
x
Reference in New Issue
Block a user