diff --git a/README.md b/README.md index 5af6b07f..26bc9721 100644 --- a/README.md +++ b/README.md @@ -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 | diff --git a/src/ceval.h b/src/ceval.h index c1a19f2e..2ada8589 100644 --- a/src/ceval.h +++ b/src/ceval.h @@ -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; itry_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); diff --git a/src/compiler.h b/src/compiler.h index 9fd2fd58..74236444 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -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() { diff --git a/src/opcodes.h b/src/opcodes.h index 2d572211..4a44f38a 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -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) diff --git a/src/vm.h b/src/vm.h index dfcc703c..3b661168 100644 --- a/src/vm.h +++ b/src/vm.h @@ -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 iter = vm->PyIter_AS_C(val); + for(int i=0; itp_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{ diff --git a/tests/_star.py b/tests/_star.py index b3eecd60..550a4fa8 100644 --- a/tests/_star.py +++ b/tests/_star.py @@ -18,4 +18,18 @@ def f(a, b, *args, c=16): assert f(1, 2, 3, 4) == 26 assert f(1, 2, 3, 4, c=32) == 42 -assert f(*a, c=-26) == 0 \ No newline at end of file +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 == [] \ No newline at end of file