mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 19:40:18 +00:00
fix forloop
This commit is contained in:
parent
f3d876c5ef
commit
5706e5e49d
@ -316,6 +316,7 @@ int py_tuple__len(const py_Ref self);
|
|||||||
|
|
||||||
// unchecked functions, if self is not a list, the behavior is undefined
|
// unchecked functions, if self is not a list, the behavior is undefined
|
||||||
py_ObjectRef py_list__getitem(const py_Ref self, int i);
|
py_ObjectRef py_list__getitem(const py_Ref self, int i);
|
||||||
|
py_ObjectRef py_list__data(const py_Ref self);
|
||||||
void py_list__setitem(py_Ref self, int i, const py_Ref val);
|
void py_list__setitem(py_Ref self, int i, const py_Ref val);
|
||||||
void py_list__delitem(py_Ref self, int i);
|
void py_list__delitem(py_Ref self, int i);
|
||||||
int py_list__len(const py_Ref self);
|
int py_list__len(const py_Ref self);
|
||||||
|
@ -85,12 +85,7 @@ OPCODE(UNARY_STAR)
|
|||||||
OPCODE(UNARY_INVERT)
|
OPCODE(UNARY_INVERT)
|
||||||
/**************************/
|
/**************************/
|
||||||
OPCODE(GET_ITER)
|
OPCODE(GET_ITER)
|
||||||
OPCODE(GET_ITER_NEW)
|
|
||||||
OPCODE(FOR_ITER)
|
OPCODE(FOR_ITER)
|
||||||
OPCODE(FOR_ITER_STORE_FAST)
|
|
||||||
OPCODE(FOR_ITER_STORE_GLOBAL)
|
|
||||||
OPCODE(FOR_ITER_YIELD_VALUE)
|
|
||||||
OPCODE(FOR_ITER_UNPACK)
|
|
||||||
/**************************/
|
/**************************/
|
||||||
OPCODE(IMPORT_PATH)
|
OPCODE(IMPORT_PATH)
|
||||||
OPCODE(POP_IMPORT_STAR)
|
OPCODE(POP_IMPORT_STAR)
|
||||||
|
@ -87,7 +87,6 @@ static int Ctx__add_varname(Ctx* self, py_Name name);
|
|||||||
static int Ctx__add_const(Ctx* self, py_Ref);
|
static int Ctx__add_const(Ctx* self, py_Ref);
|
||||||
static int Ctx__add_const_string(Ctx* self, c11_sv);
|
static int Ctx__add_const_string(Ctx* self, c11_sv);
|
||||||
static void Ctx__emit_store_name(Ctx* self, NameScope scope, py_Name name, int line);
|
static void Ctx__emit_store_name(Ctx* self, NameScope scope, py_Name name, int line);
|
||||||
static void Ctx__try_merge_for_iter_store(Ctx* self, int);
|
|
||||||
static void Ctx__s_emit_top(Ctx*); // emit top -> pop -> delete
|
static void Ctx__s_emit_top(Ctx*); // emit top -> pop -> delete
|
||||||
static void Ctx__s_push(Ctx*, Expr*); // push
|
static void Ctx__s_push(Ctx*, Expr*); // push
|
||||||
static Expr* Ctx__s_top(Ctx*); // top
|
static Expr* Ctx__s_top(Ctx*); // top
|
||||||
@ -440,12 +439,7 @@ bool TupleExpr__emit_store(Expr* self_, Ctx* ctx) {
|
|||||||
// build tuple and unpack it is meaningless
|
// build tuple and unpack it is meaningless
|
||||||
Ctx__revert_last_emit_(ctx);
|
Ctx__revert_last_emit_(ctx);
|
||||||
} else {
|
} else {
|
||||||
if(prev->op == OP_FOR_ITER) {
|
Ctx__emit_(ctx, OP_UNPACK_SEQUENCE, self->items.count, self->line);
|
||||||
prev->op = OP_FOR_ITER_UNPACK;
|
|
||||||
prev->arg = self->items.count;
|
|
||||||
} else {
|
|
||||||
Ctx__emit_(ctx, OP_UNPACK_SEQUENCE, self->items.count, self->line);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// starred assignment target must be in a tuple
|
// starred assignment target must be in a tuple
|
||||||
@ -541,11 +535,10 @@ void CompExpr__emit_(Expr* self_, Ctx* ctx) {
|
|||||||
Ctx__emit_(ctx, OP_GET_ITER, BC_NOARG, BC_KEEPLINE);
|
Ctx__emit_(ctx, OP_GET_ITER, BC_NOARG, BC_KEEPLINE);
|
||||||
Ctx__enter_block(ctx, CodeBlockType_FOR_LOOP);
|
Ctx__enter_block(ctx, CodeBlockType_FOR_LOOP);
|
||||||
int curr_iblock = ctx->curr_iblock;
|
int curr_iblock = ctx->curr_iblock;
|
||||||
int for_codei = Ctx__emit_(ctx, OP_FOR_ITER, curr_iblock, BC_KEEPLINE);
|
Ctx__emit_(ctx, OP_FOR_ITER, curr_iblock, BC_KEEPLINE);
|
||||||
bool ok = vtemit_store(self->vars, ctx);
|
bool ok = vtemit_store(self->vars, ctx);
|
||||||
// this error occurs in `vars` instead of this line, but...nevermind
|
// this error occurs in `vars` instead of this line, but...nevermind
|
||||||
assert(ok); // this should raise a SyntaxError, but we just assert it
|
assert(ok); // this should raise a SyntaxError, but we just assert it
|
||||||
Ctx__try_merge_for_iter_store(ctx, for_codei);
|
|
||||||
if(self->cond) {
|
if(self->cond) {
|
||||||
vtemit_(self->cond, ctx);
|
vtemit_(self->cond, ctx);
|
||||||
int patch = Ctx__emit_(ctx, OP_POP_JUMP_IF_FALSE, BC_NOARG, BC_KEEPLINE);
|
int patch = Ctx__emit_(ctx, OP_POP_JUMP_IF_FALSE, BC_NOARG, BC_KEEPLINE);
|
||||||
@ -1309,26 +1302,6 @@ static void Ctx__revert_last_emit_(Ctx* self) {
|
|||||||
c11_vector__pop(&self->co->codes_ex);
|
c11_vector__pop(&self->co->codes_ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Ctx__try_merge_for_iter_store(Ctx* self, int i) {
|
|
||||||
// [FOR_ITER, STORE_?, ]
|
|
||||||
Bytecode* co_codes = (Bytecode*)self->co->codes.data;
|
|
||||||
if(co_codes[i].op != OP_FOR_ITER) return;
|
|
||||||
if(self->co->codes.count - i != 2) return;
|
|
||||||
uint16_t arg = co_codes[i + 1].arg;
|
|
||||||
if(co_codes[i + 1].op == OP_STORE_FAST) {
|
|
||||||
Ctx__revert_last_emit_(self);
|
|
||||||
co_codes[i].op = OP_FOR_ITER_STORE_FAST;
|
|
||||||
co_codes[i].arg = arg;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(co_codes[i + 1].op == OP_STORE_GLOBAL) {
|
|
||||||
Ctx__revert_last_emit_(self);
|
|
||||||
co_codes[i].op = OP_FOR_ITER_STORE_GLOBAL;
|
|
||||||
co_codes[i].arg = arg;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int Ctx__emit_int(Ctx* self, int64_t value, int line) {
|
static int Ctx__emit_int(Ctx* self, int64_t value, int line) {
|
||||||
if(is_small_int(value)) {
|
if(is_small_int(value)) {
|
||||||
return Ctx__emit_(self, OP_LOAD_SMALL_INT, (uint16_t)value, line);
|
return Ctx__emit_(self, OP_LOAD_SMALL_INT, (uint16_t)value, line);
|
||||||
@ -1569,18 +1542,22 @@ static Error* EXPR_TUPLE(Compiler* self) { return EXPR_TUPLE_ALLOW_SLICE(self, f
|
|||||||
|
|
||||||
// special case for `for loop` and `comp`
|
// special case for `for loop` and `comp`
|
||||||
static Error* EXPR_VARS(Compiler* self) {
|
static Error* EXPR_VARS(Compiler* self) {
|
||||||
// int count = 0;
|
int count = 0;
|
||||||
// do {
|
do {
|
||||||
// consume(TK_ID);
|
consume(TK_ID);
|
||||||
// ctx()->s_push(make_expr<NameExpr>(prev().str(), name_scope()));
|
py_Name name = py_name2(Token__sv(prev()));
|
||||||
// count += 1;
|
NameExpr* e = NameExpr__new(prev()->line, name, name_scope(self));
|
||||||
// } while(match(TK_COMMA));
|
Ctx__s_push(ctx(), (Expr*)e);
|
||||||
// if(count > 1){
|
count += 1;
|
||||||
// TupleExpr* e = make_expr<TupleExpr>(count);
|
} while(match(TK_COMMA));
|
||||||
// for(int i=count-1; i>=0; i--)
|
if(count > 1) {
|
||||||
// e->items[i] = Ctx__s_popx(ctx());
|
SequenceExpr* e = TupleExpr__new(prev()->line, count);
|
||||||
// ctx()->s_push(e);
|
for(int i = count - 1; i >= 0; i--) {
|
||||||
// }
|
Expr* item = Ctx__s_popx(ctx());
|
||||||
|
c11__setitem(Expr*, &e->items, i, item);
|
||||||
|
}
|
||||||
|
Ctx__s_push(ctx(), (Expr*)e);
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1627,7 +1604,7 @@ static Error* pop_context(Compiler* self) {
|
|||||||
if(func) {
|
if(func) {
|
||||||
// check generator
|
// check generator
|
||||||
c11__foreach(Bytecode, &func->code.codes, bc) {
|
c11__foreach(Bytecode, &func->code.codes, bc) {
|
||||||
if(bc->op == OP_YIELD_VALUE || bc->op == OP_FOR_ITER_YIELD_VALUE) {
|
if(bc->op == OP_YIELD_VALUE) {
|
||||||
func->type = FuncType_GENERATOR;
|
func->type = FuncType_GENERATOR;
|
||||||
c11__foreach(Bytecode, &func->code.codes, bc) {
|
c11__foreach(Bytecode, &func->code.codes, bc) {
|
||||||
if(bc->op == OP_RETURN_VALUE && bc->arg == BC_NOARG) {
|
if(bc->op == OP_RETURN_VALUE && bc->arg == BC_NOARG) {
|
||||||
@ -2104,18 +2081,16 @@ static Error* compile_for_loop(Compiler* self) {
|
|||||||
consume(TK_IN);
|
consume(TK_IN);
|
||||||
check(EXPR_TUPLE(self)); // [vars, iter]
|
check(EXPR_TUPLE(self)); // [vars, iter]
|
||||||
Ctx__s_emit_top(ctx()); // [vars]
|
Ctx__s_emit_top(ctx()); // [vars]
|
||||||
Ctx__emit_(ctx(), OP_GET_ITER_NEW, BC_NOARG, BC_KEEPLINE);
|
Ctx__emit_(ctx(), OP_GET_ITER, BC_NOARG, BC_KEEPLINE);
|
||||||
CodeBlock* block = Ctx__enter_block(ctx(), CodeBlockType_FOR_LOOP);
|
CodeBlock* block = Ctx__enter_block(ctx(), CodeBlockType_FOR_LOOP);
|
||||||
int for_codei = Ctx__emit_(ctx(), OP_FOR_ITER, ctx()->curr_iblock, BC_KEEPLINE);
|
Ctx__emit_(ctx(), OP_FOR_ITER, ctx()->curr_iblock, BC_KEEPLINE);
|
||||||
Expr* vars = Ctx__s_popx(ctx());
|
Expr* vars = Ctx__s_popx(ctx());
|
||||||
bool ok = vtemit_store(vars, ctx());
|
bool ok = vtemit_store(vars, ctx());
|
||||||
vtdelete(vars);
|
vtdelete(vars);
|
||||||
if(!ok)
|
if(!ok) {
|
||||||
return SyntaxError(); // this error occurs in `vars` instead of this line, but...nevermind
|
// this error occurs in `vars` instead of this line, but...nevermind
|
||||||
|
return SyntaxError();
|
||||||
// TODO: ??
|
}
|
||||||
// ctx()->try_merge_for_iter_store(for_codei);
|
|
||||||
|
|
||||||
check(compile_block_body(self, compile_stmt));
|
check(compile_block_body(self, compile_stmt));
|
||||||
Ctx__emit_virtual(ctx(), OP_LOOP_CONTINUE, Ctx__get_loop(ctx()), BC_KEEPLINE, true);
|
Ctx__emit_virtual(ctx(), OP_LOOP_CONTINUE, Ctx__get_loop(ctx()), BC_KEEPLINE, true);
|
||||||
Ctx__exit_block(ctx());
|
Ctx__exit_block(ctx());
|
||||||
@ -2506,9 +2481,10 @@ static Error* compile_stmt(Compiler* self) {
|
|||||||
if(self->contexts.count <= 1) return SyntaxError("'yield from' outside function");
|
if(self->contexts.count <= 1) return SyntaxError("'yield from' outside function");
|
||||||
check(EXPR_TUPLE(self));
|
check(EXPR_TUPLE(self));
|
||||||
Ctx__s_emit_top(ctx());
|
Ctx__s_emit_top(ctx());
|
||||||
Ctx__emit_(ctx(), OP_GET_ITER_NEW, BC_NOARG, kw_line);
|
Ctx__emit_(ctx(), OP_GET_ITER, BC_NOARG, kw_line);
|
||||||
Ctx__enter_block(ctx(), CodeBlockType_FOR_LOOP);
|
Ctx__enter_block(ctx(), CodeBlockType_FOR_LOOP);
|
||||||
Ctx__emit_(ctx(), OP_FOR_ITER_YIELD_VALUE, BC_NOARG, kw_line);
|
Ctx__emit_(ctx(), OP_FOR_ITER, ctx()->curr_iblock, kw_line);
|
||||||
|
Ctx__emit_(ctx(), OP_YIELD_VALUE, BC_NOARG, kw_line);
|
||||||
Ctx__emit_(ctx(), OP_LOOP_CONTINUE, Ctx__get_loop(ctx()), kw_line);
|
Ctx__emit_(ctx(), OP_LOOP_CONTINUE, Ctx__get_loop(ctx()), kw_line);
|
||||||
Ctx__exit_block(ctx());
|
Ctx__exit_block(ctx());
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
@ -2687,7 +2663,7 @@ Error* Compiler__compile(Compiler* self, CodeObject* out) {
|
|||||||
} else if(mode() == JSON_MODE) {
|
} else if(mode() == JSON_MODE) {
|
||||||
check(EXPR(self));
|
check(EXPR(self));
|
||||||
Expr* e = Ctx__s_popx(ctx());
|
Expr* e = Ctx__s_popx(ctx());
|
||||||
if(!e->vt->is_json_object) { return SyntaxError("expect a JSON object, literal or array"); }
|
if(!e->vt->is_json_object) return SyntaxError("expect a JSON object, literal or array");
|
||||||
consume(TK_EOF);
|
consume(TK_EOF);
|
||||||
vtemit_(e, ctx());
|
vtemit_(e, ctx());
|
||||||
Ctx__emit_(ctx(), OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
|
Ctx__emit_(ctx(), OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
|
||||||
|
@ -709,9 +709,24 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
|||||||
*TOP() = self->last_retval;
|
*TOP() = self->last_retval;
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
////////////////
|
||||||
//
|
case OP_GET_ITER: {
|
||||||
|
if(!py_iter(TOP())) goto __ERROR;
|
||||||
|
*TOP() = *py_retval();
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
case OP_FOR_ITER: {
|
||||||
|
int res = py_next(TOP());
|
||||||
|
if(res == -1) goto __ERROR;
|
||||||
|
if(res) {
|
||||||
|
PUSH(py_retval());
|
||||||
|
DISPATCH();
|
||||||
|
} else {
|
||||||
|
int target = Frame__prepare_loop_break(frame, &self->stack);
|
||||||
|
DISPATCH_JUMP_ABSOLUTE(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////
|
||||||
case OP_UNPACK_SEQUENCE: {
|
case OP_UNPACK_SEQUENCE: {
|
||||||
if(!stack_unpack_sequence(self, byte.arg)) goto __ERROR;
|
if(!stack_unpack_sequence(self, byte.arg)) goto __ERROR;
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
|
@ -24,6 +24,11 @@ void py_newlistn(py_Ref out, int n) {
|
|||||||
userdata->count = n;
|
userdata->count = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
py_Ref py_list__data(const py_Ref self) {
|
||||||
|
List* userdata = py_touserdata(self);
|
||||||
|
return userdata->data;
|
||||||
|
}
|
||||||
|
|
||||||
py_Ref py_list__getitem(const py_Ref self, int i) {
|
py_Ref py_list__getitem(const py_Ref self, int i) {
|
||||||
List* userdata = py_touserdata(self);
|
List* userdata = py_touserdata(self);
|
||||||
return c11__at(py_TValue, userdata, i);
|
return c11__at(py_TValue, userdata, i);
|
||||||
|
@ -38,7 +38,7 @@ const char* pk_opname(Opcode op) {
|
|||||||
py_TValue* pk_arrayview(py_Ref self, int* length) {
|
py_TValue* pk_arrayview(py_Ref self, int* length) {
|
||||||
if(self->type == tp_list) {
|
if(self->type == tp_list) {
|
||||||
*length = py_list__len(self);
|
*length = py_list__len(self);
|
||||||
return py_list__getitem(self, 0);
|
return py_list__data(self);
|
||||||
}
|
}
|
||||||
if(self->type == tp_tuple) {
|
if(self->type == tp_tuple) {
|
||||||
*length = py_tuple__len(self);
|
*length = py_tuple__len(self);
|
||||||
@ -137,8 +137,7 @@ static void disassemble(CodeObject* co) {
|
|||||||
case OP_BEGIN_CLASS:
|
case OP_BEGIN_CLASS:
|
||||||
case OP_GOTO:
|
case OP_GOTO:
|
||||||
case OP_DELETE_GLOBAL:
|
case OP_DELETE_GLOBAL:
|
||||||
case OP_STORE_CLASS_ATTR:
|
case OP_STORE_CLASS_ATTR: {
|
||||||
case OP_FOR_ITER_STORE_GLOBAL: {
|
|
||||||
c11_sbuf__write_cstr(&ss, " (");
|
c11_sbuf__write_cstr(&ss, " (");
|
||||||
c11_sbuf__write_cstr(&ss, py_name2str(byte.arg));
|
c11_sbuf__write_cstr(&ss, py_name2str(byte.arg));
|
||||||
c11_sbuf__write_char(&ss, ')');
|
c11_sbuf__write_char(&ss, ')');
|
||||||
@ -146,8 +145,7 @@ static void disassemble(CodeObject* co) {
|
|||||||
}
|
}
|
||||||
case OP_LOAD_FAST:
|
case OP_LOAD_FAST:
|
||||||
case OP_STORE_FAST:
|
case OP_STORE_FAST:
|
||||||
case OP_DELETE_FAST:
|
case OP_DELETE_FAST: {
|
||||||
case OP_FOR_ITER_STORE_FAST: {
|
|
||||||
py_Name name = c11__getitem(py_Name, &co->varnames, byte.arg);
|
py_Name name = c11__getitem(py_Name, &co->varnames, byte.arg);
|
||||||
c11_sbuf__write_cstr(&ss, " (");
|
c11_sbuf__write_cstr(&ss, " (");
|
||||||
c11_sbuf__write_cstr(&ss, py_name2str(name));
|
c11_sbuf__write_cstr(&ss, py_name2str(name));
|
||||||
|
@ -71,15 +71,6 @@ assert d == 1
|
|||||||
d = 1 if 2 < 1 else 2
|
d = 1 if 2 < 1 else 2
|
||||||
assert d == 2
|
assert d == 2
|
||||||
|
|
||||||
t = 0
|
|
||||||
for i in range(5):
|
|
||||||
try:
|
|
||||||
break
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
t = 1
|
|
||||||
assert t == 0
|
|
||||||
|
|
||||||
t = 0
|
t = 0
|
||||||
for i in range(5):
|
for i in range(5):
|
||||||
if True and 1:
|
if True and 1:
|
||||||
@ -131,4 +122,13 @@ if x == 2:
|
|||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
x = 3
|
x = 3
|
||||||
assert x == 2
|
assert x == 2
|
||||||
|
|
||||||
|
# t = 0
|
||||||
|
# for i in range(5):
|
||||||
|
# try:
|
||||||
|
# break
|
||||||
|
# except:
|
||||||
|
# pass
|
||||||
|
# t = 1
|
||||||
|
# assert t == 0
|
Loading…
x
Reference in New Issue
Block a user