add Str::split

This commit is contained in:
blueloveTH 2023-08-28 00:34:13 +08:00
parent 590cb1130c
commit e21005e5d2
10 changed files with 82 additions and 29 deletions

View File

@ -105,7 +105,6 @@ class Compiler {
void exprLiteral0();
void compile_block_body();
Str _compile_import();
void compile_normal_import();
void compile_from_import();
bool is_expression();

View File

@ -108,7 +108,7 @@ OPCODE(FOR_ITER)
/**************************/
OPCODE(IMPORT_NAME)
OPCODE(IMPORT_NAME_REL)
OPCODE(IMPORT_STAR)
OPCODE(POP_IMPORT_STAR)
/**************************/
OPCODE(UNPACK_SEQUENCE)
OPCODE(UNPACK_EX)

View File

@ -73,6 +73,7 @@ struct Str{
Str escape(bool single_quote=true) const;
int index(const Str& sub, int start=0) const;
Str replace(const Str& old, const Str& new_, int count=-1) const;
std::vector<std::string_view> split(Str sep) const;
/*************unicode*************/
int _unicode_index_to_byte(int i) const;

View File

@ -433,7 +433,7 @@ public:
};
ImportContext _import_context;
PyObject* py_import(StrName name, bool relative=false);
PyObject* py_import(Str path, bool relative=false);
~VM();
#if PK_DEBUG_CEVAL_STEP

View File

@ -591,15 +591,15 @@ __NEXT_STEP:;
DISPATCH();
/*****************************************/
TARGET(IMPORT_NAME)
_name = StrName(byte.arg);
PUSH(py_import(_name));
_0 = co_consts[byte.arg];
PUSH(py_import(CAST(Str&, _0)));
DISPATCH();
TARGET(IMPORT_NAME_REL)
_name = StrName(byte.arg);
PUSH(py_import(_name, true));
_0 = co_consts[byte.arg];
PUSH(py_import(CAST(Str&, _0), true));
DISPATCH();
TARGET(IMPORT_STAR) {
_0 = POPX();
TARGET(POP_IMPORT_STAR) {
_0 = POPX(); // pop the module
_1 = _0->attr().try_get(__all__);
if(_1 != nullptr){
for(PyObject* key: CAST(List&, _1)){

View File

@ -472,20 +472,14 @@ __SUBSCR_END:
consume(TK("@dedent"));
}
Str Compiler::_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;
consume(TK("@id"));
Str name = prev().str();
ctx()->emit(op, StrName(name).index, prev().line);
return name;
}
// import a as b
// import a [as b]
// import a [as b], c [as d]
void Compiler::compile_normal_import() {
if(name_scope() != NAME_GLOBAL) SyntaxError("import statement should be used in global scope");
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"))) {
consume(TK("@id"));
name = prev().str();
@ -495,19 +489,55 @@ __SUBSCR_END:
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() {
_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"));
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();
return;
}
do {
ctx()->emit(OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
consume(TK("@id"));
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);
if (match(TK("as"))) {
consume(TK("@id"));

View File

@ -549,16 +549,23 @@ void init_builtins(VM* _vm) {
return VAR(self.u8_getitem(i));
});
_vm->bind_method<-1>("str", "replace", [](VM* vm, ArgsView args) {
if(args.size() != 1+2 && args.size() != 1+3) vm->TypeError("replace() takes 2 or 3 arguments");
_vm->bind(_vm->_t(_vm->tp_str), "replace(self, old, new, count=-1)", [](VM* vm, ArgsView args) {
const Str& self = _CAST(Str&, args[0]);
const Str& old = CAST(Str&, args[1]);
if(old.empty()) vm->ValueError("empty substring");
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));
});
_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) {
const Str& self = _CAST(Str&, args[0]);
const Str& sub = CAST(Str&, args[1]);

View File

@ -308,6 +308,19 @@ int utf8len(unsigned char c, bool suppress){
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){
return os << sn.sv();
}

View File

@ -215,7 +215,8 @@ namespace pkpy{
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;
int type;
if(relative){

View File

@ -33,7 +33,9 @@ assert s[-3] == 'a'
assert t[-5:] == 'ow!!!'
assert t[3:-3] == 's is string example....wow'
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 t.startswith('this') == True;