impl starred unpack

This commit is contained in:
blueloveTH 2023-02-24 01:24:51 +08:00
parent 5e15d526a0
commit 256f9af147
6 changed files with 48 additions and 32 deletions

View File

@ -35,7 +35,7 @@ Please see https://pocketpy.dev for details or try [Live Demo](https://bluelovet
| Dict | `{'a': 1, 'b': 2}` | YES |
| F-String | `f'value is {x}'` | YES |
| Unpacking | `a, b = 1, 2` | YES |
| Star Unpacking | `a, *b = [1, 2, 3]` | NO |
| Star Unpacking | `a, *b = [1, 2, 3]` | YES |
| Exception | `raise/try..catch` | YES |
| Dynamic Code | `eval()/exec()` | YES |
| Reflection | `hasattr()/getattr()/setattr()` | YES |

View File

@ -44,8 +44,8 @@ PyVar VM::run_frame(Frame* frame){
case OP_BUILD_INDEX: {
PyVar index = frame->pop_value(this);
auto ref = IndexRef(frame->pop_value(this), index);
if(byte.arg == 0) frame->push(PyRef(ref));
else frame->push(ref.get(this, frame));
if(byte.arg > 0) frame->push(ref.get(this, frame));
else frame->push(PyRef(ref));
} continue;
case OP_FAST_INDEX: case OP_FAST_INDEX_REF: {
auto& a = frame->co->names[byte.arg & 0xFFFF];
@ -65,18 +65,13 @@ PyVar VM::run_frame(Frame* frame){
PyRef_AS_C(frame->top())->del(this, frame);
frame->_pop();
continue;
case OP_BUILD_SMART_TUPLE: {
case OP_BUILD_TUPLE: {
pkpy::Args items = frame->pop_n_reversed(byte.arg);
bool done = false;
for(int i=0; i<items.size(); i++){
if(!is_type(items[i], tp_ref)) {
done = true;
for(int j=i; j<items.size(); j++) frame->try_deref(this, items[j]);
frame->push(PyTuple(std::move(items)));
break;
}
}
if(!done) frame->push(PyRef(TupleRef(std::move(items))));
frame->push(PyTuple(std::move(items)));
} continue;
case OP_BUILD_TUPLE_REF: {
pkpy::Args items = frame->pop_n_reversed(byte.arg);
frame->push(PyRef(TupleRef(std::move(items))));
} continue;
case OP_BUILD_STRING: {
pkpy::Args items = frame->pop_n_values_reversed(this, byte.arg);

View File

@ -436,7 +436,7 @@ private:
EXPR(); // NOTE: "1," will fail, "1,2" will be ok
size++;
} while(match(TK(",")));
emit(OP_BUILD_SMART_TUPLE, size);
emit(co()->_rvalue ? OP_BUILD_TUPLE : OP_BUILD_TUPLE_REF, size);
}
void exprOr() {
@ -813,7 +813,7 @@ __LISTCOMP:
consume(TK("@id"));
_exprName(true); size++;
} while (match(TK(",")));
if(size > 1) emit(OP_BUILD_SMART_TUPLE, size);
if(size > 1) emit(OP_BUILD_TUPLE_REF, size);
}
void compile_for_loop() {

View File

@ -24,7 +24,8 @@ OPCODE(BUILD_MAP)
OPCODE(BUILD_SET)
OPCODE(BUILD_SLICE)
OPCODE(BUILD_CLASS)
OPCODE(BUILD_SMART_TUPLE)
OPCODE(BUILD_TUPLE)
OPCODE(BUILD_TUPLE_REF)
OPCODE(BUILD_STRING)
OPCODE(LIST_APPEND)

View File

@ -859,21 +859,27 @@ PyVar TupleRef::get(VM* vm, Frame* frame) const{
}
void TupleRef::set(VM* vm, Frame* frame, PyVar val) const{
#define TUPLE_REF_SET() \
if(args.size() > objs.size()) vm->ValueError("too many values to unpack"); \
if(args.size() < objs.size()) vm->ValueError("not enough values to unpack"); \
for (int i = 0; i < objs.size(); i++) vm->PyRef_AS_C(objs[i])->set(vm, frame, args[i]);
if(is_type(val, vm->tp_tuple)){
const pkpy::Tuple& args = OBJ_GET(pkpy::Tuple, val);
TUPLE_REF_SET()
}else if(is_type(val, vm->tp_list)){
const pkpy::List& args = OBJ_GET(pkpy::List, val);
TUPLE_REF_SET()
}else{
vm->TypeError("only tuple or list can be unpacked");
val = vm->asIter(val);
pkpy::shared_ptr<BaseIter> iter = vm->PyIter_AS_C(val);
for(int i=0; i<objs.size(); i++){
PyVarOrNull x;
if(is_type(objs[i], vm->tp_star_wrapper)){
auto& star = vm->PyStarWrapper_AS_C(objs[i]);
if(star.rvalue) vm->ValueError("can't use starred expression here");
if(i != objs.size()-1) vm->ValueError("* can only be used at the end");
auto ref = vm->PyRef_AS_C(star.obj);
pkpy::List list;
while((x = iter->next()) != nullptr) list.push_back(x);
ref->set(vm, frame, vm->PyList(std::move(list)));
return;
}else{
x = iter->next();
if(x == nullptr) vm->ValueError("not enough values to unpack");
vm->PyRef_AS_C(objs[i])->set(vm, frame, x);
}
}
#undef TUPLE_REF_SET
PyVarOrNull x = iter->next();
if(x != nullptr) vm->ValueError("too many values to unpack");
}
void TupleRef::del(VM* vm, Frame* frame) const{

View File

@ -19,3 +19,17 @@ assert f(1, 2, 3, 4) == 26
assert f(1, 2, 3, 4, c=32) == 42
assert f(*a, c=-26) == 0
a, b = 1, 2
a, b = b, a
assert a == 2
assert b == 1
a, *b = 1, 2, 3, 4
assert a == 1
assert b == [2, 3, 4]
a, *b = [1]
assert a == 1
assert b == []