diff --git a/src/ceval.h b/src/ceval.h index 2a7a1308..526850e4 100644 --- a/src/ceval.h +++ b/src/ceval.h @@ -238,6 +238,7 @@ __NEXT_STEP:; frame->push(std::move(ret)); } DISPATCH(); case OP_RETURN_VALUE: return frame->popx(); + case OP_YIELD_VALUE: return _py_op_yield; /*****************************************/ case OP_LIST_APPEND: { PyObject* obj = frame->popx(); @@ -352,35 +353,39 @@ __NEXT_STEP:; cls->attr().set(name, obj); } DISPATCH(); /*****************************************/ - /*****************************************/ - /*****************************************/ - // case OP_SETUP_DECORATOR: DISPATCH(); - - // case OP_ASSERT: { - // PyObject* _msg = frame->pop_value(this); - // Str msg = CAST(Str, asStr(_msg)); - // PyObject* expr = frame->pop_value(this); - // if(asBool(expr) != True) _error("AssertionError", msg); - // } DISPATCH(); - // case OP_EXCEPTION_MATCH: { - // const auto& e = CAST(Exception&, frame->top()); - // StrName name = frame->co->names[byte.arg].first; - // frame->push(VAR(e.match_type(name))); - // } DISPATCH(); - // case OP_RAISE: { - // PyObject* obj = frame->pop_value(this); - // Str msg = obj == None ? "" : CAST(Str, asStr(obj)); - // StrName type = frame->co->names[byte.arg].first; - // _error(type, msg); - // } DISPATCH(); - // case OP_RE_RAISE: _raise(); DISPATCH(); - // case OP_YIELD_VALUE: return _py_op_yield; // // TODO: using "goto" inside with block may cause __exit__ not called // case OP_WITH_ENTER: call(frame->pop_value(this), __enter__, no_arg()); DISPATCH(); // case OP_WITH_EXIT: call(frame->pop_value(this), __exit__, no_arg()); DISPATCH(); - // case OP_TRY_BLOCK_ENTER: frame->on_try_block_enter(); DISPATCH(); - // case OP_TRY_BLOCK_EXIT: frame->on_try_block_exit(); DISPATCH(); - default: throw std::runtime_error(Str("opcode ") + OP_NAMES[byte.op] + " is not implemented"); + /*****************************************/ + case OP_TRY_BLOCK_ENTER: frame->on_try_block_enter(); DISPATCH(); + case OP_TRY_BLOCK_EXIT: frame->on_try_block_exit(); DISPATCH(); + /*****************************************/ + case OP_ASSERT: { + PyObject* obj = frame->top(); + Str msg; + if(is_type(obj, tp_tuple)){ + auto& t = CAST(Tuple&, obj); + if(t.size() != 2) ValueError("assert tuple must have 2 elements"); + obj = t[0]; + msg = CAST(Str&, asStr(t[1])); + } + bool ok = asBool(obj); + frame->pop(); + if(!ok) _error("AssertionError", msg); + } DISPATCH(); + case OP_EXCEPTION_MATCH: { + const auto& e = CAST(Exception&, frame->top()); + StrName name = frame->co->names[byte.arg]; + frame->push(VAR(e.match_type(name))); + } DISPATCH(); + case OP_RAISE: { + PyObject* obj = frame->popx(); + Str msg = obj == None ? "" : CAST(Str, asStr(obj)); + StrName type = frame->co->names[byte.arg]; + _error(type, msg); + } DISPATCH(); + case OP_RE_RAISE: _raise(); DISPATCH(); + default: throw std::runtime_error(OP_NAMES[byte.op] + std::string(" is not implemented")); } UNREACHABLE(); } diff --git a/src/compiler.h b/src/compiler.h index c4d2be1f..1215d4f2 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -578,13 +578,14 @@ class Compiler { } void compile_decorated(){ - EXPR(false); - // TODO: support multiple decorator - // use a while loop to consume '@' - if(!match_newlines_repl()) SyntaxError(); - ctx()->emit(OP_SETUP_DECORATOR, BC_NOARG, prev().line); + std::vector decorators; + do{ + EXPR(); + decorators.push_back(ctx()->s_expr.popx()); + if(!match_newlines_repl()) SyntaxError(); + }while(match(TK("@"))); consume(TK("def")); - compile_function(); + compile_function(decorators); } bool try_compile_assignment(){ @@ -593,6 +594,7 @@ class Compiler { switch (curr().type) { case TK("+="): case TK("-="): case TK("*="): case TK("/="): case TK("//="): case TK("%="): case TK("<<="): case TK(">>="): case TK("&="): case TK("|="): case TK("^="): { + if(ctx()->is_compiling_class) SyntaxError(); inplace = true; advance(); auto e = make_expr(); @@ -802,7 +804,7 @@ class Compiler { } while (match(TK(","))); } - void compile_function(){ + void compile_function(const std::vector& decorators={}){ // TODO: bug, if there are multiple decorators, will cause error FuncDecl_ decl = make_sp(); StrName obj_name; @@ -825,6 +827,12 @@ class Compiler { compile_block_body(); pop_context(); ctx()->emit(OP_LOAD_FUNCTION, ctx()->add_func_decl(decl), prev().line); + // add decorators + for(auto it=decorators.rbegin(); it!=decorators.rend(); ++it){ + (*it)->emit(ctx()); + ctx()->emit(OP_ROT_TWO, BC_NOARG, (*it)->line); + ctx()->emit(OP_CALL, 1, (*it)->line); + } if(!ctx()->is_compiling_class){ if(obj_name.empty()){ auto e = make_expr(decl->name, name_scope()); diff --git a/src/expr.h b/src/expr.h index bd3cfd92..da2e25ca 100644 --- a/src/expr.h +++ b/src/expr.h @@ -140,6 +140,10 @@ struct NameExpr: Expr{ bool emit_store(CodeEmitContext* ctx) override { int index = ctx->add_name(name); + if(ctx->is_compiling_class){ + ctx->emit(OP_STORE_CLASS_ATTR, index, line); + return true; + } switch(scope){ case NAME_LOCAL: ctx->emit(OP_STORE_LOCAL, index, line); diff --git a/src/opcodes.h b/src/opcodes.h index 7ba77d2a..de44b343 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -1,23 +1,5 @@ #ifdef OPCODE -/**************************/ -OPCODE(WITH_ENTER) -OPCODE(WITH_EXIT) - -OPCODE(ASSERT) -OPCODE(EXCEPTION_MATCH) -OPCODE(RAISE) -OPCODE(RE_RAISE) - -OPCODE(STORE_FUNCTION) - -OPCODE(TRY_BLOCK_ENTER) -OPCODE(TRY_BLOCK_EXIT) - -OPCODE(YIELD_VALUE) - -OPCODE(SETUP_DECORATOR) - /**************************/ OPCODE(NO_OP) /**************************/ @@ -74,6 +56,7 @@ OPCODE(CALL_UNPACK) OPCODE(CALL_KWARGS) OPCODE(CALL_KWARGS_UNPACK) OPCODE(RETURN_VALUE) +OPCODE(YIELD_VALUE) /**************************/ OPCODE(LIST_APPEND) OPCODE(DICT_ADD) @@ -92,9 +75,18 @@ OPCODE(IMPORT_STAR) OPCODE(UNPACK_SEQUENCE) OPCODE(UNPACK_EX) /**************************/ -// TODO: examine this OPCODE(BEGIN_CLASS) OPCODE(END_CLASS) OPCODE(STORE_CLASS_ATTR) /**************************/ +OPCODE(WITH_ENTER) +OPCODE(WITH_EXIT) +/**************************/ +OPCODE(TRY_BLOCK_ENTER) +OPCODE(TRY_BLOCK_EXIT) +OPCODE(ASSERT) +OPCODE(EXCEPTION_MATCH) +OPCODE(RAISE) +OPCODE(RE_RAISE) +/**************************/ #endif \ No newline at end of file