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 | | Dict | `{'a': 1, 'b': 2}` | YES |
| F-String | `f'value is {x}'` | YES | | F-String | `f'value is {x}'` | YES |
| Unpacking | `a, b = 1, 2` | 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 | | Exception | `raise/try..catch` | YES |
| Dynamic Code | `eval()/exec()` | YES | | Dynamic Code | `eval()/exec()` | YES |
| Reflection | `hasattr()/getattr()/setattr()` | YES | | Reflection | `hasattr()/getattr()/setattr()` | YES |

View File

@ -44,8 +44,8 @@ PyVar VM::run_frame(Frame* frame){
case OP_BUILD_INDEX: { case OP_BUILD_INDEX: {
PyVar index = frame->pop_value(this); PyVar index = frame->pop_value(this);
auto ref = IndexRef(frame->pop_value(this), index); auto ref = IndexRef(frame->pop_value(this), index);
if(byte.arg == 0) frame->push(PyRef(ref)); if(byte.arg > 0) frame->push(ref.get(this, frame));
else frame->push(ref.get(this, frame)); else frame->push(PyRef(ref));
} continue; } continue;
case OP_FAST_INDEX: case OP_FAST_INDEX_REF: { case OP_FAST_INDEX: case OP_FAST_INDEX_REF: {
auto& a = frame->co->names[byte.arg & 0xFFFF]; 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); PyRef_AS_C(frame->top())->del(this, frame);
frame->_pop(); frame->_pop();
continue; continue;
case OP_BUILD_SMART_TUPLE: { case OP_BUILD_TUPLE: {
pkpy::Args items = frame->pop_n_reversed(byte.arg); pkpy::Args items = frame->pop_n_reversed(byte.arg);
bool done = false; frame->push(PyTuple(std::move(items)));
for(int i=0; i<items.size(); i++){ } continue;
if(!is_type(items[i], tp_ref)) { case OP_BUILD_TUPLE_REF: {
done = true; pkpy::Args items = frame->pop_n_reversed(byte.arg);
for(int j=i; j<items.size(); j++) frame->try_deref(this, items[j]); frame->push(PyRef(TupleRef(std::move(items))));
frame->push(PyTuple(std::move(items)));
break;
}
}
if(!done) frame->push(PyRef(TupleRef(std::move(items))));
} continue; } continue;
case OP_BUILD_STRING: { case OP_BUILD_STRING: {
pkpy::Args items = frame->pop_n_values_reversed(this, byte.arg); 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 EXPR(); // NOTE: "1," will fail, "1,2" will be ok
size++; size++;
} while(match(TK(","))); } while(match(TK(",")));
emit(OP_BUILD_SMART_TUPLE, size); emit(co()->_rvalue ? OP_BUILD_TUPLE : OP_BUILD_TUPLE_REF, size);
} }
void exprOr() { void exprOr() {
@ -813,7 +813,7 @@ __LISTCOMP:
consume(TK("@id")); consume(TK("@id"));
_exprName(true); size++; _exprName(true); size++;
} while (match(TK(","))); } 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() { void compile_for_loop() {

View File

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

View File

@ -18,4 +18,18 @@ def f(a, b, *args, c=16):
assert f(1, 2, 3, 4) == 26 assert f(1, 2, 3, 4) == 26
assert f(1, 2, 3, 4, c=32) == 42 assert f(1, 2, 3, 4, c=32) == 42
assert f(*a, c=-26) == 0 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 == []