mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
add module operator
and add split
for single char
This commit is contained in:
parent
04df1dbe5b
commit
f2d5fbbb94
@ -58,12 +58,12 @@ To compile it with your project, these flags must be set:
|
|||||||
+ Exception must be enabled
|
+ Exception must be enabled
|
||||||
+ For MSVC, `/utf-8` flag must be set
|
+ For MSVC, `/utf-8` flag must be set
|
||||||
|
|
||||||
For development build on Linux, use this snippet.
|
For development build, use this snippet.
|
||||||
```bash
|
```bash
|
||||||
# prerequisites
|
# prerequisites
|
||||||
sudo apt-get install libc++-dev libc++abi-dev clang
|
pip install cmake
|
||||||
# build the repo
|
# build the repo
|
||||||
bash build.sh
|
python cmake_build.py
|
||||||
# unittest
|
# unittest
|
||||||
python scripts/run_tests.py
|
python scripts/run_tests.py
|
||||||
```
|
```
|
||||||
|
14
docs/modules/operator.md
Normal file
14
docs/modules/operator.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
icon: package
|
||||||
|
label: operator
|
||||||
|
---
|
||||||
|
|
||||||
|
The operator module exports a set of efficient functions corresponding to the intrinsic operators of Python. For example, operator.add(x, y) is equivalent to the expression x+y.
|
||||||
|
Many function names are those used for special methods, without the double underscores.
|
||||||
|
|
||||||
|
+ `operator.lt(a, b)`
|
||||||
|
+ `operator.le(a, b)`
|
||||||
|
+ `operator.eq(a, b)`
|
||||||
|
+ `operator.ne(a, b)`
|
||||||
|
+ `operator.ge(a, b)`
|
||||||
|
+ `operator.gt(a, b)`
|
@ -76,6 +76,7 @@ struct Str{
|
|||||||
Str replace(char old, char new_) const;
|
Str replace(char old, char new_) const;
|
||||||
Str replace(const Str& old, const Str& new_, int count=-1) const;
|
Str replace(const Str& old, const Str& new_, int count=-1) const;
|
||||||
std::vector<std::string_view> split(const Str& sep) const;
|
std::vector<std::string_view> split(const Str& sep) const;
|
||||||
|
std::vector<std::string_view> split(char sep) const;
|
||||||
int count(const Str& sub) const;
|
int count(const Str& sub) const;
|
||||||
|
|
||||||
/*************unicode*************/
|
/*************unicode*************/
|
||||||
|
@ -310,6 +310,7 @@ public:
|
|||||||
bool py_le(PyObject* lhs, PyObject* rhs);
|
bool py_le(PyObject* lhs, PyObject* rhs);
|
||||||
bool py_gt(PyObject* lhs, PyObject* rhs);
|
bool py_gt(PyObject* lhs, PyObject* rhs);
|
||||||
bool py_ge(PyObject* lhs, PyObject* rhs);
|
bool py_ge(PyObject* lhs, PyObject* rhs);
|
||||||
|
bool py_ne(PyObject* lhs, PyObject* rhs) { return !py_eq(lhs, rhs); }
|
||||||
|
|
||||||
template<int ARGC>
|
template<int ARGC>
|
||||||
PyObject* bind_func(Str type, Str name, NativeFuncC fn) {
|
PyObject* bind_func(Str type, Str name, NativeFuncC fn) {
|
||||||
|
@ -4,49 +4,34 @@ def print(*args, sep=' ', end='\n'):
|
|||||||
s = sep.join([str(i) for i in args])
|
s = sep.join([str(i) for i in args])
|
||||||
_sys.stdout.write(s + end)
|
_sys.stdout.write(s + end)
|
||||||
|
|
||||||
def max(*args, key=None):
|
def _minmax_reduce(op, args, key):
|
||||||
if key is None:
|
if key is None:
|
||||||
|
if len(args) == 2:
|
||||||
|
return args[0] if op(args[0], args[1]) else args[1]
|
||||||
key = lambda x: x
|
key = lambda x: x
|
||||||
if len(args) == 0:
|
if len(args) == 0:
|
||||||
raise TypeError('max 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]
|
||||||
if len(args) == 2:
|
|
||||||
a, b = args
|
|
||||||
return a if key(a) > key(b) else b
|
|
||||||
args = iter(args)
|
args = iter(args)
|
||||||
res = next(args)
|
res = next(args)
|
||||||
if res is StopIteration:
|
if res is StopIteration:
|
||||||
raise ValueError('max() arg is an empty sequence')
|
raise ValueError('args is an empty sequence')
|
||||||
while True:
|
while True:
|
||||||
i = next(args)
|
i = next(args)
|
||||||
if i is StopIteration:
|
if i is StopIteration:
|
||||||
break
|
break
|
||||||
if 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):
|
||||||
if key is None:
|
from operator import lt
|
||||||
key = lambda x: x
|
return _minmax_reduce(lt, args, key)
|
||||||
if len(args) == 0:
|
|
||||||
raise TypeError('min expected 1 arguments, got 0')
|
def max(*args, key=None):
|
||||||
if len(args) == 1:
|
from operator import gt
|
||||||
args = args[0]
|
return _minmax_reduce(gt, args, key)
|
||||||
if len(args) == 2:
|
|
||||||
a, b = args
|
|
||||||
return a if key(a) < key(b) else b
|
|
||||||
args = iter(args)
|
|
||||||
res = next(args)
|
|
||||||
if res is StopIteration:
|
|
||||||
raise ValueError('min() arg is an empty sequence')
|
|
||||||
while True:
|
|
||||||
i = next(args)
|
|
||||||
if i is StopIteration:
|
|
||||||
break
|
|
||||||
if key(i) < key(res):
|
|
||||||
res = i
|
|
||||||
return res
|
|
||||||
|
|
||||||
def all(iterable):
|
def all(iterable):
|
||||||
for i in iterable:
|
for i in iterable:
|
||||||
@ -96,9 +81,9 @@ def reversed(iterable):
|
|||||||
a.reverse()
|
a.reverse()
|
||||||
return a
|
return a
|
||||||
|
|
||||||
def sorted(iterable, reverse=False, key=None):
|
def sorted(iterable, key=None, reverse=False):
|
||||||
a = list(iterable)
|
a = list(iterable)
|
||||||
a.sort(reverse=reverse, key=key)
|
a.sort(key=key, reverse=reverse)
|
||||||
return a
|
return a
|
||||||
|
|
||||||
##### str #####
|
##### str #####
|
||||||
|
@ -623,7 +623,14 @@ void init_builtins(VM* _vm) {
|
|||||||
|
|
||||||
_vm->bind(_vm->_t(_vm->tp_str), "split(self, sep=' ')", [](VM* vm, ArgsView args) {
|
_vm->bind(_vm->_t(_vm->tp_str), "split(self, sep=' ')", [](VM* vm, ArgsView args) {
|
||||||
const Str& self = _CAST(Str&, args[0]);
|
const Str& self = _CAST(Str&, args[0]);
|
||||||
std::vector<std::string_view> parts = self.split(CAST(Str&, args[1]));
|
const Str& sep = CAST(Str&, args[1]);
|
||||||
|
if(sep.empty()) vm->ValueError("empty separator");
|
||||||
|
std::vector<std::string_view> parts;
|
||||||
|
if(sep.size == 1){
|
||||||
|
parts = self.split(sep[0]);
|
||||||
|
}else{
|
||||||
|
parts = self.split(sep);
|
||||||
|
}
|
||||||
List ret(parts.size());
|
List ret(parts.size());
|
||||||
for(int i=0; i<parts.size(); i++) ret[i] = VAR(Str(parts[i]));
|
for(int i=0; i<parts.size(); i++) ret[i] = VAR(Str(parts[i]));
|
||||||
return VAR(std::move(ret));
|
return VAR(std::move(ret));
|
||||||
@ -1401,6 +1408,16 @@ void add_module_timeit(VM* vm){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add_module_operator(VM* vm){
|
||||||
|
PyObject* mod = vm->new_module("operator");
|
||||||
|
vm->bind_func<2>(mod, "lt", [](VM* vm, ArgsView args) { return VAR(vm->py_lt(args[0], args[1]));});
|
||||||
|
vm->bind_func<2>(mod, "le", [](VM* vm, ArgsView args) { return VAR(vm->py_le(args[0], args[1]));});
|
||||||
|
vm->bind_func<2>(mod, "eq", [](VM* vm, ArgsView args) { return VAR(vm->py_eq(args[0], args[1]));});
|
||||||
|
vm->bind_func<2>(mod, "ne", [](VM* vm, ArgsView args) { return VAR(vm->py_ne(args[0], args[1]));});
|
||||||
|
vm->bind_func<2>(mod, "ge", [](VM* vm, ArgsView args) { return VAR(vm->py_ge(args[0], args[1]));});
|
||||||
|
vm->bind_func<2>(mod, "gt", [](VM* vm, ArgsView args) { return VAR(vm->py_gt(args[0], args[1]));});
|
||||||
|
}
|
||||||
|
|
||||||
struct PyStructTime{
|
struct PyStructTime{
|
||||||
PY_CLASS(PyStructTime, time, struct_time)
|
PY_CLASS(PyStructTime, time, struct_time)
|
||||||
|
|
||||||
@ -1702,6 +1719,7 @@ void VM::post_init(){
|
|||||||
add_module_random(this);
|
add_module_random(this);
|
||||||
add_module_base64(this);
|
add_module_base64(this);
|
||||||
add_module_timeit(this);
|
add_module_timeit(this);
|
||||||
|
add_module_operator(this);
|
||||||
|
|
||||||
for(const char* name: {"this", "functools", "heapq", "bisect", "pickle", "_long", "colorsys", "typing", "datetime"}){
|
for(const char* name: {"this", "functools", "heapq", "bisect", "pickle", "_long", "colorsys", "typing", "datetime"}){
|
||||||
_lazy_modules[name] = kPythonLibs[name];
|
_lazy_modules[name] = kPythonLibs[name];
|
||||||
|
14
src/str.cpp
14
src/str.cpp
@ -344,6 +344,20 @@ int utf8len(unsigned char c, bool suppress){
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string_view> Str::split(char sep) const{
|
||||||
|
std::vector<std::string_view> result;
|
||||||
|
int i = 0;
|
||||||
|
for(int j = 0; j < size; j++){
|
||||||
|
if(data[j] == sep){
|
||||||
|
if(j > i) result.emplace_back(data+i, j-i);
|
||||||
|
i = j + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(size > i) result.emplace_back(data+i, size-i);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int Str::count(const Str& sub) const{
|
int Str::count(const Str& sub) const{
|
||||||
if(sub.empty()) return size + 1;
|
if(sub.empty()) return size + 1;
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
|
19
src/vm.cpp
19
src/vm.cpp
@ -287,7 +287,7 @@ namespace pkpy{
|
|||||||
|
|
||||||
PyObject* VM::py_import(Str path, bool throw_err){
|
PyObject* VM::py_import(Str path, bool throw_err){
|
||||||
if(path.empty()) vm->ValueError("empty module name");
|
if(path.empty()) vm->ValueError("empty module name");
|
||||||
auto f_join = [](const std::vector<std::string_view>& cpnts){
|
static auto f_join = [](const std::vector<std::string_view>& cpnts){
|
||||||
SStream ss;
|
SStream ss;
|
||||||
for(int i=0; i<cpnts.size(); i++){
|
for(int i=0; i<cpnts.size(); i++){
|
||||||
if(i != 0) ss << ".";
|
if(i != 0) ss << ".";
|
||||||
@ -303,7 +303,7 @@ namespace pkpy{
|
|||||||
Str curr_path = _import_context.pending.back();
|
Str curr_path = _import_context.pending.back();
|
||||||
bool curr_is_init = _import_context.pending_is_init.back();
|
bool curr_is_init = _import_context.pending_is_init.back();
|
||||||
// convert relative path to absolute path
|
// convert relative path to absolute path
|
||||||
std::vector<std::string_view> cpnts = curr_path.split(".");
|
std::vector<std::string_view> cpnts = curr_path.split('.');
|
||||||
int prefix = 0; // how many dots in the prefix
|
int prefix = 0; // how many dots in the prefix
|
||||||
for(int i=0; i<path.length(); i++){
|
for(int i=0; i<path.length(); i++){
|
||||||
if(path[i] == '.') prefix++;
|
if(path[i] == '.') prefix++;
|
||||||
@ -316,22 +316,19 @@ namespace pkpy{
|
|||||||
path = f_join(cpnts);
|
path = f_join(cpnts);
|
||||||
}
|
}
|
||||||
|
|
||||||
// std::cout << "py_import(" << path.escape() << ")" << std::endl;
|
PK_ASSERT(path.begin()[0] != '.' && path.end()[-1] != '.');
|
||||||
|
|
||||||
PK_ASSERT(path.begin()[0] != '.');
|
// check existing module
|
||||||
PK_ASSERT(path.end()[-1] != '.');
|
StrName name(path);
|
||||||
|
PyObject* ext_mod = _modules.try_get(name);
|
||||||
auto path_cpnts = path.split(".");
|
if(ext_mod != nullptr) return ext_mod;
|
||||||
|
|
||||||
|
std::vector<std::string_view> path_cpnts = path.split('.');
|
||||||
// check circular import
|
// check circular import
|
||||||
if(_import_context.pending.size() > 128){
|
if(_import_context.pending.size() > 128){
|
||||||
ImportError("maximum recursion depth exceeded while importing");
|
ImportError("maximum recursion depth exceeded while importing");
|
||||||
}
|
}
|
||||||
|
|
||||||
StrName name(path); // path to StrName
|
|
||||||
PyObject* ext_mod = _modules.try_get(name);
|
|
||||||
if(ext_mod != nullptr) return ext_mod;
|
|
||||||
|
|
||||||
// try import
|
// try import
|
||||||
Str filename = path.replace('.', kPlatformSep) + ".py";
|
Str filename = path.replace('.', kPlatformSep) + ".py";
|
||||||
Str source;
|
Str source;
|
||||||
|
@ -47,6 +47,9 @@ assert 'foo!!bar!!baz'.split('!!') == ['foo', 'bar', 'baz']
|
|||||||
assert ' 4 3 '.split() == ['4', '3']
|
assert ' 4 3 '.split() == ['4', '3']
|
||||||
assert ' 4 3 '.split(' ') == ['4', '3']
|
assert ' 4 3 '.split(' ') == ['4', '3']
|
||||||
|
|
||||||
|
x = 'aa bb cccc'
|
||||||
|
assert x.split('cc') == ['aa bb ']
|
||||||
|
|
||||||
assert '111'.count('1') == 3
|
assert '111'.count('1') == 3
|
||||||
assert '111'.count('11') == 1
|
assert '111'.count('11') == 1
|
||||||
assert '1111'.count('11') == 2
|
assert '1111'.count('11') == 2
|
||||||
|
@ -925,7 +925,7 @@ assert min([1, 2], key=lambda x: -x) == 2
|
|||||||
assert max(1, 2) == 2
|
assert max(1, 2) == 2
|
||||||
assert max(1, 2, 3) == 3
|
assert max(1, 2, 3) == 3
|
||||||
assert max([1, 2]) == 2
|
assert max([1, 2]) == 2
|
||||||
assert max([1, 2], key=lambda x: -x) == 1
|
assert max([1, 2, 3], key=lambda x: -x) == 1
|
||||||
|
|
||||||
assert min([
|
assert min([
|
||||||
(1, 2),
|
(1, 2),
|
||||||
@ -933,6 +933,9 @@ assert min([
|
|||||||
(1, 4),
|
(1, 4),
|
||||||
]) == (1, 2)
|
]) == (1, 2)
|
||||||
|
|
||||||
|
assert min(1, 2) == 1
|
||||||
|
assert max(1, 2) == 2
|
||||||
|
|
||||||
|
|
||||||
# test callable
|
# test callable
|
||||||
assert callable(lambda: 1) is True # function
|
assert callable(lambda: 1) is True # function
|
||||||
|
Loading…
x
Reference in New Issue
Block a user