This commit is contained in:
blueloveTH 2023-04-02 21:37:10 +08:00
parent ebe3193327
commit 718ba988d5
3 changed files with 77 additions and 58 deletions

View File

@ -448,8 +448,9 @@ class Compiler {
consume(TK("@id"));
name = prev().str();
}
int index = ctx()->add_name(name, name_scope());
ctx()->emit(OP_STORE_NAME, index, prev().line);
int index = ctx()->add_name(name);
auto op = name_scope()==NAME_LOCAL ? OP_STORE_LOCAL : OP_STORE_GLOBAL;
ctx()->emit(op, index, prev().line);
} while (match(TK(",")));
consume_end_stmt();
}
@ -459,8 +460,8 @@ class Compiler {
_compile_import();
consume(TK("import"));
if (match(TK("*"))) {
if(name_scope() != NAME_GLOBAL) SyntaxError("import * can only be used in global scope");
ctx()->emit(OP_STORE_ALL_NAMES, BC_NOARG, prev().line);
if(name_scope() != NAME_GLOBAL) SyntaxError("import * should be used in global scope");
ctx()->emit(OP_IMPORT_STAR, BC_NOARG, prev().line);
consume_end_stmt();
return;
}
@ -475,7 +476,8 @@ class Compiler {
name = prev().str();
}
index = ctx()->add_name(name);
ctx()->emit(OP_STORE_GLOBAL, index, prev().line);
auto op = name_scope()==NAME_LOCAL ? OP_STORE_LOCAL : OP_STORE_GLOBAL;
ctx()->emit(op, index, prev().line);
} while (match(TK(",")));
ctx()->emit(OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
consume_end_stmt();
@ -527,6 +529,7 @@ class Compiler {
ctx()->exit_block();
}
// PASS
void compile_for_loop() {
EXPR_TUPLE();
Expr_ vars = ctx()->s_expr.popx();
@ -535,42 +538,39 @@ class Compiler {
ctx()->emit(OP_GET_ITER, BC_NOARG, BC_KEEPLINE);
ctx()->enter_block(FOR_LOOP);
ctx()->emit(OP_FOR_ITER, BC_NOARG, BC_KEEPLINE);
// set variables and handle implicit unpack
bool ok = vars->emit_store(ctx());
// this error occurs in `vars` instead of this line
// but...nevermind
if(!ok) SyntaxError();
if(!ok) SyntaxError(); // this error occurs in `vars` instead of this line, but...nevermind
compile_block_body();
ctx()->emit(OP_LOOP_CONTINUE, BC_NOARG, BC_KEEPLINE);
ctx()->exit_block();
}
void compile_try_except() {
ctx()->enter_block(TRY_EXCEPT);
ctx()->emit(OP_TRY_BLOCK_ENTER, BC_NOARG, prev().line);
compile_block_body();
ctx()->emit(OP_TRY_BLOCK_EXIT, BC_NOARG, BC_KEEPLINE);
std::vector<int> patches = {
ctx()->emit(OP_JUMP_ABSOLUTE, BC_NOARG, BC_KEEPLINE)
};
ctx()->exit_block();
// ctx()->enter_block(TRY_EXCEPT);
// ctx()->emit(OP_TRY_BLOCK_ENTER, BC_NOARG, prev().line);
// compile_block_body();
// ctx()->emit(OP_TRY_BLOCK_EXIT, BC_NOARG, BC_KEEPLINE);
// std::vector<int> patches = {
// ctx()->emit(OP_JUMP_ABSOLUTE, BC_NOARG, BC_KEEPLINE)
// };
// ctx()->exit_block();
do {
consume(TK("except"));
if(match(TK("@id"))){
int name_idx = ctx()->add_name(prev().str(), NAME_SPECIAL);
emit(OP_EXCEPTION_MATCH, name_idx);
}else{
emit(OP_LOAD_TRUE);
}
int patch = emit(OP_POP_JUMP_IF_FALSE);
emit(OP_POP_TOP); // pop the exception on match
compile_block_body();
patches.push_back(emit(OP_JUMP_ABSOLUTE));
patch_jump(patch);
}while(curr().type == TK("except"));
emit(OP_RE_RAISE); // no match, re-raise
for (int patch : patches) patch_jump(patch);
// do {
// consume(TK("except"));
// if(match(TK("@id"))){
// int name_idx = ctx()->add_name(prev().str(), NAME_SPECIAL);
// emit(OP_EXCEPTION_MATCH, name_idx);
// }else{
// emit(OP_LOAD_TRUE);
// }
// int patch = emit(OP_POP_JUMP_IF_FALSE);
// emit(OP_POP_TOP); // pop the exception on match
// compile_block_body();
// patches.push_back(emit(OP_JUMP_ABSOLUTE));
// patch_jump(patch);
// }while(curr().type == TK("except"));
// emit(OP_RE_RAISE); // no match, re-raise
// for (int patch : patches) patch_jump(patch);
}
void compile_decorated(){
@ -650,13 +650,13 @@ class Compiler {
case TK("global"):
do {
consume(TK("@id"));
co()->global_names.insert(prev().str());
ctx()->co->global_names.insert(prev().str());
} while (match(TK(",")));
consume_end_stmt();
break;
case TK("raise"): {
consume(TK("@id"));
int dummy_t = ctx()->add_name(prev().str(), NAME_SPECIAL);
int dummy_t = ctx()->add_name(prev().str());
if(match(TK("(")) && !match(TK(")"))){
EXPR(false); consume(TK(")"));
}else{
@ -688,17 +688,17 @@ class Compiler {
} break;
/*************************************************/
// TODO: refactor goto/label use special $ syntax
case TK("label"):
case TK("label"): {
if(mode()!=EXEC_MODE) SyntaxError("'label' is only available in EXEC_MODE");
consume(TK(".")); consume(TK("@id"));
bool ok = ctx()->add_label(prev().str());
if(!ok) SyntaxError("label " + prev().str().escape(true) + " already exists");
consume_end_stmt();
break;
} break;
case TK("goto"):
if(mode()!=EXEC_MODE) SyntaxError("'goto' is only available in EXEC_MODE");
consume(TK(".")); consume(TK("@id"));
emit(OP_GOTO, co()->add_name(prev().str(), NAME_SPECIAL));
ctx()->emit(OP_GOTO, ctx()->add_name(prev().str()), prev().line);
consume_end_stmt();
break;
/*************************************************/
@ -707,9 +707,9 @@ class Compiler {
EXPR_TUPLE(true);
if(!try_compile_assignment()){
if(mode()==REPL_MODE && name_scope()==NAME_GLOBAL){
emit(OP_PRINT_EXPR, BC_NOARG, BC_KEEPLINE);
ctx()->emit(OP_PRINT_EXPR, BC_NOARG, BC_KEEPLINE);
}else{
emit(OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
ctx()->emit(OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
}
}
consume_end_stmt();
@ -717,21 +717,22 @@ class Compiler {
}
}
// PASS
void compile_class(){
consume(TK("@id"));
int cls_name_idx = co()->add_name(prev().str(), NAME_GLOBAL);
int super_cls_name_idx = -1;
int namei = ctx()->add_name(prev().str());
int super_namei = -1;
if(match(TK("(")) && match(TK("@id"))){
super_cls_name_idx = co()->add_name(prev().str(), NAME_GLOBAL);
super_namei = ctx()->add_name(prev().str());
consume(TK(")"));
}
if(super_cls_name_idx == -1) emit(OP_LOAD_NONE);
else emit(OP_LOAD_NAME, super_cls_name_idx);
emit(OP_BEGIN_CLASS, cls_name_idx);
if(super_namei == -1) ctx()->emit(OP_LOAD_NONE, BC_NOARG, prev().line);
else ctx()->emit(OP_LOAD_NAME, super_namei, prev().line);
ctx()->emit(OP_BEGIN_CLASS, namei, BC_KEEPLINE);
ctx()->is_compiling_class = true;
compile_block_body();
ctx()->is_compiling_class = false;
emit(OP_END_CLASS);
ctx()->emit(OP_END_CLASS, BC_NOARG, BC_KEEPLINE);
}
void _compile_f_args(Function& func, bool enable_type_hints){

View File

@ -23,7 +23,7 @@ struct Expr{
virtual bool emit_del(CodeEmitContext* ctx) { return false; }
// for OP_STORE_XXX
virtual bool emit_store(CodeEmitContext* ctx) { return false; }
[[nodiscard]] virtual bool emit_store(CodeEmitContext* ctx) { return false; }
};
struct CodeEmitContext{
@ -153,15 +153,12 @@ struct StarredExpr: Expr{
void emit(CodeEmitContext* ctx) override {
child->emit(ctx);
// as a rvalue, we should do unpack here
//ctx->emit(OP_UNARY_STAR, (int)false, line);
ctx->emit(OP_UNARY_STAR, BC_NOARG, line);
}
bool emit_store(CodeEmitContext* ctx) override {
child->emit(ctx);
// as a lvalue, we should do pack here
//ctx->emit(OP_UNARY_STAR, (int)true, line);
return true;
// simply proxy to child
return child->emit_store(ctx);
}
};
@ -368,10 +365,29 @@ struct TupleExpr: SequenceExpr{
Opcode opcode() const override { return OP_BUILD_TUPLE; }
bool emit_store(CodeEmitContext* ctx) override {
// assume TOS is an iterable
// unpack it and emit several OP_STORE
// https://docs.python.org/3/library/dis.html#opcode-UNPACK_SEQUENCE
// https://docs.python.org/3/library/dis.html#opcode-UNPACK_EX
// TOS is an iterable
// items may contain StarredExpr, we should check it
int starred_i = -1;
for(int i=0; i<items.size(); i++){
if(!items[i]->is_starred()) continue;
if(starred_i == -1) starred_i = i;
else return false; // multiple StarredExpr not allowed
}
if(starred_i == -1){
// Unpacks TOS into count individual values, which are put onto the stack right-to-left.
ctx->emit(OP_UNPACK_SEQUENCE, items.size(), line);
}else{
// starred assignment target must be in a tuple
if(items.size() == 1) return false;
// starred assignment target must be the last one (differ from CPython)
if(starred_i != items.size()-1) return false;
ctx->emit(OP_UNPACK_EX, items.size()-1, line);
}
for(auto& e: items){
bool ok = e->emit_store(ctx);
if(!ok) return false;
}
return true;
}

View File

@ -94,5 +94,7 @@ OPCODE(FOR_ITER)
OPCODE(IMPORT_NAME)
OPCODE(IMPORT_STAR)
/**************************/
OPCODE(UNPACK_SEQUENCE)
OPCODE(UNPACK_EX)
/**************************/
#endif