mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
add Str::split
This commit is contained in:
parent
590cb1130c
commit
e21005e5d2
@ -105,7 +105,6 @@ class Compiler {
|
|||||||
void exprLiteral0();
|
void exprLiteral0();
|
||||||
|
|
||||||
void compile_block_body();
|
void compile_block_body();
|
||||||
Str _compile_import();
|
|
||||||
void compile_normal_import();
|
void compile_normal_import();
|
||||||
void compile_from_import();
|
void compile_from_import();
|
||||||
bool is_expression();
|
bool is_expression();
|
||||||
|
@ -108,7 +108,7 @@ OPCODE(FOR_ITER)
|
|||||||
/**************************/
|
/**************************/
|
||||||
OPCODE(IMPORT_NAME)
|
OPCODE(IMPORT_NAME)
|
||||||
OPCODE(IMPORT_NAME_REL)
|
OPCODE(IMPORT_NAME_REL)
|
||||||
OPCODE(IMPORT_STAR)
|
OPCODE(POP_IMPORT_STAR)
|
||||||
/**************************/
|
/**************************/
|
||||||
OPCODE(UNPACK_SEQUENCE)
|
OPCODE(UNPACK_SEQUENCE)
|
||||||
OPCODE(UNPACK_EX)
|
OPCODE(UNPACK_EX)
|
||||||
|
@ -73,6 +73,7 @@ struct Str{
|
|||||||
Str escape(bool single_quote=true) const;
|
Str escape(bool single_quote=true) const;
|
||||||
int index(const Str& sub, int start=0) const;
|
int index(const Str& sub, int start=0) 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(Str sep) const;
|
||||||
|
|
||||||
/*************unicode*************/
|
/*************unicode*************/
|
||||||
int _unicode_index_to_byte(int i) const;
|
int _unicode_index_to_byte(int i) const;
|
||||||
|
@ -433,7 +433,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
ImportContext _import_context;
|
ImportContext _import_context;
|
||||||
PyObject* py_import(StrName name, bool relative=false);
|
PyObject* py_import(Str path, bool relative=false);
|
||||||
~VM();
|
~VM();
|
||||||
|
|
||||||
#if PK_DEBUG_CEVAL_STEP
|
#if PK_DEBUG_CEVAL_STEP
|
||||||
|
@ -591,15 +591,15 @@ __NEXT_STEP:;
|
|||||||
DISPATCH();
|
DISPATCH();
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
TARGET(IMPORT_NAME)
|
TARGET(IMPORT_NAME)
|
||||||
_name = StrName(byte.arg);
|
_0 = co_consts[byte.arg];
|
||||||
PUSH(py_import(_name));
|
PUSH(py_import(CAST(Str&, _0)));
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
TARGET(IMPORT_NAME_REL)
|
TARGET(IMPORT_NAME_REL)
|
||||||
_name = StrName(byte.arg);
|
_0 = co_consts[byte.arg];
|
||||||
PUSH(py_import(_name, true));
|
PUSH(py_import(CAST(Str&, _0), true));
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
TARGET(IMPORT_STAR) {
|
TARGET(POP_IMPORT_STAR) {
|
||||||
_0 = POPX();
|
_0 = POPX(); // pop the module
|
||||||
_1 = _0->attr().try_get(__all__);
|
_1 = _0->attr().try_get(__all__);
|
||||||
if(_1 != nullptr){
|
if(_1 != nullptr){
|
||||||
for(PyObject* key: CAST(List&, _1)){
|
for(PyObject* key: CAST(List&, _1)){
|
||||||
|
@ -472,20 +472,14 @@ __SUBSCR_END:
|
|||||||
consume(TK("@dedent"));
|
consume(TK("@dedent"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Str Compiler::_compile_import() {
|
// import a [as b]
|
||||||
if(name_scope() != NAME_GLOBAL) SyntaxError("import statement should be used in global scope");
|
// import a [as b], c [as d]
|
||||||
Opcode op = OP_IMPORT_NAME;
|
|
||||||
if(match(TK("."))) op = OP_IMPORT_NAME_REL;
|
|
||||||
consume(TK("@id"));
|
|
||||||
Str name = prev().str();
|
|
||||||
ctx()->emit(op, StrName(name).index, prev().line);
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
// import a as b
|
|
||||||
void Compiler::compile_normal_import() {
|
void Compiler::compile_normal_import() {
|
||||||
|
if(name_scope() != NAME_GLOBAL) SyntaxError("import statement should be used in global scope");
|
||||||
do {
|
do {
|
||||||
Str name = _compile_import();
|
consume(TK("@id"));
|
||||||
|
Str name = prev().str();
|
||||||
|
ctx()->emit(OP_IMPORT_NAME, ctx()->add_const(VAR(name)), prev().line);
|
||||||
if (match(TK("as"))) {
|
if (match(TK("as"))) {
|
||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
name = prev().str();
|
name = prev().str();
|
||||||
@ -495,19 +489,55 @@ __SUBSCR_END:
|
|||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
}
|
}
|
||||||
|
|
||||||
// from a import b as c, d as e
|
// from a import b [as c], d [as e]
|
||||||
|
// from a.b import c [as d]
|
||||||
|
// from . import a [as b]
|
||||||
|
// from .a import b [as c]
|
||||||
|
// from .a.b import c [as d]
|
||||||
|
// from xxx import *
|
||||||
void Compiler::compile_from_import() {
|
void Compiler::compile_from_import() {
|
||||||
_compile_import();
|
if(name_scope() != NAME_GLOBAL) SyntaxError("import statement should be used in global scope");
|
||||||
|
Opcode op = OP_IMPORT_NAME;
|
||||||
|
if(match(TK("."))) op = OP_IMPORT_NAME_REL;
|
||||||
|
std::vector<Str> parts;
|
||||||
|
|
||||||
|
if(op == OP_IMPORT_NAME_REL){
|
||||||
|
if(match(TK("@id"))){
|
||||||
|
parts.push_back(prev().str());
|
||||||
|
while (match(TK("."))) {
|
||||||
|
consume(TK("@id"));
|
||||||
|
parts.push_back(prev().str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
consume(TK("@id"));
|
||||||
|
parts.push_back(prev().str());
|
||||||
|
while (match(TK("."))) {
|
||||||
|
consume(TK("@id"));
|
||||||
|
parts.push_back(prev().str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FastStrStream ss;
|
||||||
|
for (int i=0; i<parts.size(); i++) {
|
||||||
|
if(i > 0) ss << ".";
|
||||||
|
ss << parts[i];
|
||||||
|
}
|
||||||
|
ctx()->emit(op, ctx()->add_const(VAR(ss.str())), prev().line);
|
||||||
consume(TK("import"));
|
consume(TK("import"));
|
||||||
|
|
||||||
if (match(TK("*"))) {
|
if (match(TK("*"))) {
|
||||||
ctx()->emit(OP_IMPORT_STAR, BC_NOARG, prev().line);
|
// pop the module and import __all__
|
||||||
|
ctx()->emit(OP_POP_IMPORT_STAR, BC_NOARG, prev().line);
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
ctx()->emit(OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit(OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
|
||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
Str name = prev().str();
|
Str name = prev().str();
|
||||||
|
// module's __getattr__ should be customized or use a new opcode...
|
||||||
ctx()->emit(OP_LOAD_ATTR, StrName(name).index, prev().line);
|
ctx()->emit(OP_LOAD_ATTR, StrName(name).index, prev().line);
|
||||||
if (match(TK("as"))) {
|
if (match(TK("as"))) {
|
||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
|
@ -549,16 +549,23 @@ void init_builtins(VM* _vm) {
|
|||||||
return VAR(self.u8_getitem(i));
|
return VAR(self.u8_getitem(i));
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_method<-1>("str", "replace", [](VM* vm, ArgsView args) {
|
_vm->bind(_vm->_t(_vm->tp_str), "replace(self, old, new, count=-1)", [](VM* vm, ArgsView args) {
|
||||||
if(args.size() != 1+2 && args.size() != 1+3) vm->TypeError("replace() takes 2 or 3 arguments");
|
|
||||||
const Str& self = _CAST(Str&, args[0]);
|
const Str& self = _CAST(Str&, args[0]);
|
||||||
const Str& old = CAST(Str&, args[1]);
|
const Str& old = CAST(Str&, args[1]);
|
||||||
if(old.empty()) vm->ValueError("empty substring");
|
if(old.empty()) vm->ValueError("empty substring");
|
||||||
const Str& new_ = CAST(Str&, args[2]);
|
const Str& new_ = CAST(Str&, args[2]);
|
||||||
int count = args.size()==1+3 ? CAST(int, args[3]) : -1;
|
int count = CAST(int, args[3]);
|
||||||
return VAR(self.replace(old, new_, count));
|
return VAR(self.replace(old, new_, count));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
_vm->bind(_vm->_t(_vm->tp_str), "split(self, sep=' ')", [](VM* vm, ArgsView args) {
|
||||||
|
const Str& self = _CAST(Str&, args[0]);
|
||||||
|
std::vector<std::string_view> parts = self.split(CAST(Str&, args[1]));
|
||||||
|
List ret(parts.size());
|
||||||
|
for(int i=0; i<parts.size(); i++) ret[i] = VAR(Str(parts[i]));
|
||||||
|
return VAR(std::move(ret));
|
||||||
|
});
|
||||||
|
|
||||||
_vm->bind_method<1>("str", "index", [](VM* vm, ArgsView args) {
|
_vm->bind_method<1>("str", "index", [](VM* vm, ArgsView args) {
|
||||||
const Str& self = _CAST(Str&, args[0]);
|
const Str& self = _CAST(Str&, args[0]);
|
||||||
const Str& sub = CAST(Str&, args[1]);
|
const Str& sub = CAST(Str&, args[1]);
|
||||||
|
13
src/str.cpp
13
src/str.cpp
@ -308,6 +308,19 @@ int utf8len(unsigned char c, bool suppress){
|
|||||||
return _byte_index_to_unicode(size);
|
return _byte_index_to_unicode(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string_view> Str::split(Str sep) const{
|
||||||
|
std::vector<std::string_view> result;
|
||||||
|
int start = 0;
|
||||||
|
while(true){
|
||||||
|
int i = index(sep, start);
|
||||||
|
if(i == -1) break;
|
||||||
|
result.push_back(sv().substr(start, i - start));
|
||||||
|
start = i + sep.size;
|
||||||
|
}
|
||||||
|
result.push_back(sv().substr(start, size - start));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const StrName& sn){
|
std::ostream& operator<<(std::ostream& os, const StrName& sn){
|
||||||
return os << sn.sv();
|
return os << sn.sv();
|
||||||
}
|
}
|
||||||
|
@ -215,7 +215,8 @@ namespace pkpy{
|
|||||||
return call_method(obj, __next__);
|
return call_method(obj, __next__);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject* VM::py_import(StrName name, bool relative){
|
PyObject* VM::py_import(Str name, bool relative){
|
||||||
|
// path is '.' separated
|
||||||
Str filename;
|
Str filename;
|
||||||
int type;
|
int type;
|
||||||
if(relative){
|
if(relative){
|
||||||
|
@ -33,7 +33,9 @@ assert s[-3] == 'a'
|
|||||||
assert t[-5:] == 'ow!!!'
|
assert t[-5:] == 'ow!!!'
|
||||||
assert t[3:-3] == 's is string example....wow'
|
assert t[3:-3] == 's is string example....wow'
|
||||||
assert s > q;assert s < r
|
assert s > q;assert s < r
|
||||||
assert s.replace("foo","ball") == "balltball"
|
assert s.replace("o","") == "ftball"
|
||||||
|
assert s.replace("o","O",1) == "fOotball"
|
||||||
|
assert s.replace("foo","ball",1) == "balltball"
|
||||||
assert s.startswith('f') == True;assert s.endswith('o') == False
|
assert s.startswith('f') == True;assert s.endswith('o') == False
|
||||||
assert t.startswith('this') == True;
|
assert t.startswith('this') == True;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user