mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-19 19:10:17 +00:00
impl starred unpack
This commit is contained in:
parent
5e15d526a0
commit
256f9af147
@ -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 |
|
||||
|
21
src/ceval.h
21
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; 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);
|
||||
|
@ -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() {
|
||||
|
@ -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)
|
||||
|
34
src/vm.h
34
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<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{
|
||||
|
@ -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
|
||||
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 == []
|
Loading…
x
Reference in New Issue
Block a user