mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
fix inplace op
This commit is contained in:
parent
0da5644db5
commit
370e3e5e11
@ -65,6 +65,7 @@ struct Expr{
|
|||||||
virtual bool is_literal() const { return false; }
|
virtual bool is_literal() const { return false; }
|
||||||
virtual bool is_json_object() const { return false; }
|
virtual bool is_json_object() const { return false; }
|
||||||
virtual bool is_attrib() const { return false; }
|
virtual bool is_attrib() const { return false; }
|
||||||
|
virtual bool is_subscr() const { return false; }
|
||||||
virtual bool is_compare() const { return false; }
|
virtual bool is_compare() const { return false; }
|
||||||
virtual int star_level() const { return 0; }
|
virtual int star_level() const { return 0; }
|
||||||
virtual bool is_tuple() const { return false; }
|
virtual bool is_tuple() const { return false; }
|
||||||
@ -80,6 +81,14 @@ struct Expr{
|
|||||||
[[nodiscard]] virtual bool emit_store(CodeEmitContext* ctx) {
|
[[nodiscard]] virtual bool emit_store(CodeEmitContext* ctx) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void emit_inplace(CodeEmitContext* ctx) {
|
||||||
|
emit_(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] virtual bool emit_store_inplace(CodeEmitContext* ctx) {
|
||||||
|
return emit_store(ctx);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CodeEmitContext{
|
struct CodeEmitContext{
|
||||||
@ -316,9 +325,13 @@ struct FStringExpr: Expr{
|
|||||||
struct SubscrExpr: Expr{
|
struct SubscrExpr: Expr{
|
||||||
Expr_ a;
|
Expr_ a;
|
||||||
Expr_ b;
|
Expr_ b;
|
||||||
|
bool is_subscr() const override { return true; }
|
||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
bool emit_del(CodeEmitContext* ctx) override;
|
bool emit_del(CodeEmitContext* ctx) override;
|
||||||
bool emit_store(CodeEmitContext* ctx) override;
|
bool emit_store(CodeEmitContext* ctx) override;
|
||||||
|
|
||||||
|
void emit_inplace(CodeEmitContext* ctx) override;
|
||||||
|
bool emit_store_inplace(CodeEmitContext* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AttribExpr: Expr{
|
struct AttribExpr: Expr{
|
||||||
@ -330,7 +343,10 @@ struct AttribExpr: Expr{
|
|||||||
bool emit_del(CodeEmitContext* ctx) override;
|
bool emit_del(CodeEmitContext* ctx) override;
|
||||||
bool emit_store(CodeEmitContext* ctx) override;
|
bool emit_store(CodeEmitContext* ctx) override;
|
||||||
void emit_method(CodeEmitContext* ctx);
|
void emit_method(CodeEmitContext* ctx);
|
||||||
|
|
||||||
bool is_attrib() const override { return true; }
|
bool is_attrib() const override { return true; }
|
||||||
|
void emit_inplace(CodeEmitContext* ctx) override;
|
||||||
|
bool emit_store_inplace(CodeEmitContext* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CallExpr: Expr{
|
struct CallExpr: Expr{
|
||||||
@ -362,6 +378,9 @@ struct BinaryExpr: Expr{
|
|||||||
TokenIndex op;
|
TokenIndex op;
|
||||||
Expr_ lhs;
|
Expr_ lhs;
|
||||||
Expr_ rhs;
|
Expr_ rhs;
|
||||||
|
bool inplace;
|
||||||
|
|
||||||
|
BinaryExpr(bool inplace=false): inplace(inplace) {}
|
||||||
bool is_compare() const override;
|
bool is_compare() const override;
|
||||||
void _emit_compare(CodeEmitContext*, small_vector_2<int, 6>&);
|
void _emit_compare(CodeEmitContext*, small_vector_2<int, 6>&);
|
||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
|
@ -5,6 +5,7 @@ OPCODE(NO_OP)
|
|||||||
/**************************/
|
/**************************/
|
||||||
OPCODE(POP_TOP)
|
OPCODE(POP_TOP)
|
||||||
OPCODE(DUP_TOP)
|
OPCODE(DUP_TOP)
|
||||||
|
OPCODE(DUP_TOP_TWO)
|
||||||
OPCODE(ROT_TWO)
|
OPCODE(ROT_TWO)
|
||||||
OPCODE(ROT_THREE)
|
OPCODE(ROT_THREE)
|
||||||
OPCODE(PRINT_EXPR)
|
OPCODE(PRINT_EXPR)
|
||||||
|
@ -137,8 +137,14 @@ __NEXT_STEP:
|
|||||||
/*****************************************/
|
/*****************************************/
|
||||||
case OP_POP_TOP: POP(); DISPATCH()
|
case OP_POP_TOP: POP(); DISPATCH()
|
||||||
case OP_DUP_TOP: PUSH(TOP()); DISPATCH()
|
case OP_DUP_TOP: PUSH(TOP()); DISPATCH()
|
||||||
|
case OP_DUP_TOP_TWO:
|
||||||
|
// [a, b]
|
||||||
|
PUSH(SECOND()); // [a, b, a]
|
||||||
|
PUSH(SECOND()); // [a, b, a, b]
|
||||||
|
DISPATCH()
|
||||||
case OP_ROT_TWO: std::swap(TOP(), SECOND()); DISPATCH()
|
case OP_ROT_TWO: std::swap(TOP(), SECOND()); DISPATCH()
|
||||||
case OP_ROT_THREE:{
|
case OP_ROT_THREE:{
|
||||||
|
// [a, b, c] -> [c, a, b]
|
||||||
PyVar _0 = TOP();
|
PyVar _0 = TOP();
|
||||||
TOP() = SECOND();
|
TOP() = SECOND();
|
||||||
SECOND() = THIRD();
|
SECOND() = THIRD();
|
||||||
|
@ -790,14 +790,16 @@ __EAT_DOTS_END:
|
|||||||
if(lhs_p->is_starred()) SyntaxError();
|
if(lhs_p->is_starred()) SyntaxError();
|
||||||
if(ctx()->is_compiling_class) SyntaxError("can't use inplace operator in class definition");
|
if(ctx()->is_compiling_class) SyntaxError("can't use inplace operator in class definition");
|
||||||
advance();
|
advance();
|
||||||
auto e = make_expr<BinaryExpr>();
|
// a[x] += 1; a and x should be evaluated only once
|
||||||
|
// a.x += 1; a should be evaluated only once
|
||||||
|
auto e = make_expr<BinaryExpr>(true); // inplace=true
|
||||||
e->op = prev().type - 1; // -1 to remove =
|
e->op = prev().type - 1; // -1 to remove =
|
||||||
e->lhs = ctx()->s_expr.popx();
|
e->lhs = ctx()->s_expr.popx();
|
||||||
EXPR_TUPLE();
|
EXPR_TUPLE();
|
||||||
e->rhs = ctx()->s_expr.popx();
|
e->rhs = ctx()->s_expr.popx();
|
||||||
if(e->is_starred()) SyntaxError();
|
if(e->rhs->is_starred()) SyntaxError();
|
||||||
e->emit_(ctx());
|
e->emit_(ctx());
|
||||||
bool ok = lhs_p->emit_store(ctx());
|
bool ok = lhs_p->emit_store_inplace(ctx());
|
||||||
if(!ok) SyntaxError();
|
if(!ok) SyntaxError();
|
||||||
} return true;
|
} return true;
|
||||||
case TK("="): {
|
case TK("="): {
|
||||||
|
31
src/expr.cpp
31
src/expr.cpp
@ -569,6 +569,20 @@ namespace pkpy{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SubscrExpr::emit_inplace(CodeEmitContext* ctx){
|
||||||
|
a->emit_(ctx);
|
||||||
|
b->emit_(ctx);
|
||||||
|
ctx->emit_(OP_DUP_TOP_TWO, BC_NOARG, line);
|
||||||
|
ctx->emit_(OP_LOAD_SUBSCR, BC_NOARG, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SubscrExpr::emit_store_inplace(CodeEmitContext* ctx){
|
||||||
|
// [a, b, val] -> [val, a, b]
|
||||||
|
ctx->emit_(OP_ROT_THREE, BC_NOARG, line);
|
||||||
|
ctx->emit_(OP_STORE_SUBSCR, BC_NOARG, line);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool SubscrExpr::emit_del(CodeEmitContext* ctx){
|
bool SubscrExpr::emit_del(CodeEmitContext* ctx){
|
||||||
a->emit_(ctx);
|
a->emit_(ctx);
|
||||||
b->emit_(ctx);
|
b->emit_(ctx);
|
||||||
@ -598,6 +612,19 @@ namespace pkpy{
|
|||||||
ctx->emit_(OP_LOAD_METHOD, b.index, line);
|
ctx->emit_(OP_LOAD_METHOD, b.index, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AttribExpr::emit_inplace(CodeEmitContext* ctx) {
|
||||||
|
a->emit_(ctx);
|
||||||
|
ctx->emit_(OP_DUP_TOP, BC_NOARG, line);
|
||||||
|
ctx->emit_(OP_LOAD_ATTR, b.index, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AttribExpr::emit_store_inplace(CodeEmitContext* ctx) {
|
||||||
|
// [a, val] -> [val, a]
|
||||||
|
ctx->emit_(OP_ROT_TWO, BC_NOARG, line);
|
||||||
|
ctx->emit_(OP_STORE_ATTR, b.index, line);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void CallExpr::emit_(CodeEmitContext* ctx) {
|
void CallExpr::emit_(CodeEmitContext* ctx) {
|
||||||
bool vargs = false;
|
bool vargs = false;
|
||||||
bool vkwargs = false;
|
bool vkwargs = false;
|
||||||
@ -689,8 +716,12 @@ namespace pkpy{
|
|||||||
// [b, RES]
|
// [b, RES]
|
||||||
}else{
|
}else{
|
||||||
// (1 + 2) < c
|
// (1 + 2) < c
|
||||||
|
if(inplace){
|
||||||
|
lhs->emit_inplace(ctx);
|
||||||
|
}else{
|
||||||
lhs->emit_(ctx);
|
lhs->emit_(ctx);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rhs->emit_(ctx);
|
rhs->emit_(ctx);
|
||||||
switch (op) {
|
switch (op) {
|
||||||
|
@ -834,7 +834,7 @@ void VM::__log_s_data(const char* title) {
|
|||||||
}
|
}
|
||||||
output.push_back(']');
|
output.push_back(']');
|
||||||
Bytecode byte = *frame->_ip;
|
Bytecode byte = *frame->_ip;
|
||||||
std::cout << output << " " << OP_NAMES[byte.op] << " " << _opcode_argstr(nullptr, byte, frame->co) << std::endl;
|
std::cout << output << " " << OP_NAMES[byte.op] << " " << _opcode_argstr(nullptr, frame->ip(), byte, frame->co) << std::endl;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -104,3 +104,14 @@ assert g(**g(**ret)) == ret
|
|||||||
|
|
||||||
# other known issues:
|
# other known issues:
|
||||||
# 1. d.extend(d) if d is deque
|
# 1. d.extend(d) if d is deque
|
||||||
|
|
||||||
|
g = 0
|
||||||
|
def test():
|
||||||
|
global g
|
||||||
|
g += 1
|
||||||
|
return g
|
||||||
|
|
||||||
|
a = [1, 10, 3]
|
||||||
|
a[test()] += 1
|
||||||
|
assert (a == [1, 11, 3]), a
|
||||||
|
assert (g == 1), g
|
||||||
|
Loading…
x
Reference in New Issue
Block a user