mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
add decorator
This commit is contained in:
parent
35435ab957
commit
c7bab88587
@ -395,3 +395,15 @@ def shuffle(L):
|
|||||||
def choice(L):
|
def choice(L):
|
||||||
return L[randint(0, len(L) - 1)]
|
return L[randint(0, len(L) - 1)]
|
||||||
)";
|
)";
|
||||||
|
|
||||||
|
const char* kFuncToolsCode = R"(
|
||||||
|
def cache(f):
|
||||||
|
def wrapper(*args):
|
||||||
|
if not hasattr(f, 'cache'):
|
||||||
|
f.cache = {}
|
||||||
|
key = args
|
||||||
|
if key not in f.cache:
|
||||||
|
f.cache[key] = f(*args)
|
||||||
|
return f.cache[key]
|
||||||
|
return wrapper
|
||||||
|
)";
|
@ -11,6 +11,7 @@ PyVar VM::run_frame(Frame* frame){
|
|||||||
switch (byte.op)
|
switch (byte.op)
|
||||||
{
|
{
|
||||||
case OP_NO_OP: continue;
|
case OP_NO_OP: continue;
|
||||||
|
case OP_SETUP_DECORATOR: continue;
|
||||||
case OP_LOAD_CONST: frame->push(frame->co->consts[byte.arg]); continue;
|
case OP_LOAD_CONST: frame->push(frame->co->consts[byte.arg]); continue;
|
||||||
case OP_LOAD_FUNCTION: {
|
case OP_LOAD_FUNCTION: {
|
||||||
const PyVar obj = frame->co->consts[byte.arg];
|
const PyVar obj = frame->co->consts[byte.arg];
|
||||||
@ -32,13 +33,11 @@ PyVar VM::run_frame(Frame* frame){
|
|||||||
auto& p = frame->co->names[byte.arg];
|
auto& p = frame->co->names[byte.arg];
|
||||||
NameRef(p).set(this, frame, frame->pop());
|
NameRef(p).set(this, frame, frame->pop());
|
||||||
} continue;
|
} continue;
|
||||||
case OP_BUILD_ATTR: {
|
case OP_BUILD_ATTR_REF: case OP_BUILD_ATTR: {
|
||||||
int name = byte.arg >> 1;
|
auto& attr = frame->co->names[byte.arg];
|
||||||
bool _rvalue = byte.arg % 2 == 1;
|
|
||||||
auto& attr = frame->co->names[name];
|
|
||||||
PyVar obj = frame->pop_value(this);
|
PyVar obj = frame->pop_value(this);
|
||||||
AttrRef ref = AttrRef(obj, NameRef(attr));
|
AttrRef ref = AttrRef(obj, NameRef(attr));
|
||||||
if(_rvalue) frame->push(ref.get(this, frame));
|
if(byte.op == OP_BUILD_ATTR) frame->push(ref.get(this, frame));
|
||||||
else frame->push(PyRef(ref));
|
else frame->push(PyRef(ref));
|
||||||
} continue;
|
} continue;
|
||||||
case OP_BUILD_INDEX: {
|
case OP_BUILD_INDEX: {
|
||||||
|
@ -206,6 +206,7 @@ private:
|
|||||||
case ')': parser->set_next_token(TK(")")); return;
|
case ')': parser->set_next_token(TK(")")); return;
|
||||||
case '[': parser->set_next_token(TK("[")); return;
|
case '[': parser->set_next_token(TK("[")); return;
|
||||||
case ']': parser->set_next_token(TK("]")); return;
|
case ']': parser->set_next_token(TK("]")); return;
|
||||||
|
case '@': parser->set_next_token(TK("@")); return;
|
||||||
case '%': parser->set_next_token_2('=', TK("%"), TK("%=")); return;
|
case '%': parser->set_next_token_2('=', TK("%"), TK("%=")); return;
|
||||||
case '&': parser->set_next_token_2('=', TK("&"), TK("&=")); return;
|
case '&': parser->set_next_token_2('=', TK("&"), TK("&=")); return;
|
||||||
case '|': parser->set_next_token_2('=', TK("|"), TK("|=")); return;
|
case '|': parser->set_next_token_2('=', TK("|"), TK("|=")); return;
|
||||||
@ -636,8 +637,7 @@ __LISTCOMP:
|
|||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
const Str& name = parser->prev.str();
|
const Str& name = parser->prev.str();
|
||||||
int index = co()->add_name(name, NAME_ATTR);
|
int index = co()->add_name(name, NAME_ATTR);
|
||||||
index = (index<<1) + (int)(co()->_rvalue>0);
|
emit(co()->_rvalue ? OP_BUILD_ATTR : OP_BUILD_ATTR_REF, index);
|
||||||
emit(OP_BUILD_ATTR, index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// [:], [:b]
|
// [:], [:b]
|
||||||
@ -746,7 +746,7 @@ __LISTCOMP:
|
|||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
Token tkname = parser->prev;
|
Token tkname = parser->prev;
|
||||||
int index = co()->add_name(tkname.str(), NAME_ATTR);
|
int index = co()->add_name(tkname.str(), NAME_ATTR);
|
||||||
emit(OP_BUILD_ATTR, (index<<1)+1);
|
emit(OP_BUILD_ATTR, index);
|
||||||
if (match(TK("as"))) {
|
if (match(TK("as"))) {
|
||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
tkname = parser->prev;
|
tkname = parser->prev;
|
||||||
@ -893,6 +893,14 @@ __LISTCOMP:
|
|||||||
compile_from_import();
|
compile_from_import();
|
||||||
} else if (match(TK("def"))){
|
} else if (match(TK("def"))){
|
||||||
compile_function();
|
compile_function();
|
||||||
|
} else if (match(TK("@"))){
|
||||||
|
EXPR();
|
||||||
|
if(!match_newlines(mode()==REPL_MODE)){
|
||||||
|
SyntaxError("expected a new line after '@'");
|
||||||
|
}
|
||||||
|
emit(OP_SETUP_DECORATOR);
|
||||||
|
consume(TK("def"));
|
||||||
|
compile_function();
|
||||||
} else if (match(TK("try"))) {
|
} else if (match(TK("try"))) {
|
||||||
compile_try_except();
|
compile_try_except();
|
||||||
} else if(match(TK("assert"))) {
|
} else if(match(TK("assert"))) {
|
||||||
@ -1020,6 +1028,7 @@ __LISTCOMP:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void compile_function(){
|
void compile_function(){
|
||||||
|
bool has_decorator = !co()->codes.empty() && co()->codes.back().op == OP_SETUP_DECORATOR;
|
||||||
if(is_compiling_class){
|
if(is_compiling_class){
|
||||||
if(match(TK("pass"))) return;
|
if(match(TK("pass"))) return;
|
||||||
consume(TK("def"));
|
consume(TK("def"));
|
||||||
@ -1047,14 +1056,19 @@ __LISTCOMP:
|
|||||||
emit(OP_LOAD_FUNCTION, co()->add_const(vm->PyFunction(func)));
|
emit(OP_LOAD_FUNCTION, co()->add_const(vm->PyFunction(func)));
|
||||||
if(name_scope() == NAME_LOCAL) emit(OP_SETUP_CLOSURE);
|
if(name_scope() == NAME_LOCAL) emit(OP_SETUP_CLOSURE);
|
||||||
if(!is_compiling_class){
|
if(!is_compiling_class){
|
||||||
if(obj_name.empty()) emit(OP_STORE_NAME, co()->add_name(func.name, name_scope()));
|
if(obj_name.empty()){
|
||||||
else {
|
if(has_decorator) emit(OP_CALL, 1);
|
||||||
|
emit(OP_STORE_NAME, co()->add_name(func.name, name_scope()));
|
||||||
|
} else {
|
||||||
|
if(has_decorator) SyntaxError("decorator is not supported here");
|
||||||
emit(OP_LOAD_NAME, co()->add_name(obj_name, name_scope()));
|
emit(OP_LOAD_NAME, co()->add_name(obj_name, name_scope()));
|
||||||
int index = co()->add_name(func.name, NAME_ATTR);
|
int index = co()->add_name(func.name, NAME_ATTR);
|
||||||
emit(OP_BUILD_ATTR, (index<<1)+0);
|
emit(OP_BUILD_ATTR_REF, index);
|
||||||
emit(OP_ROT_TWO);
|
emit(OP_ROT_TWO);
|
||||||
emit(OP_STORE_REF);
|
emit(OP_STORE_REF);
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
if(has_decorator) SyntaxError("decorator is not supported here");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +109,8 @@ struct Py_ : PyObject {
|
|||||||
_attr = new pkpy::NameDict(16, kTypeAttrLoadFactor);
|
_attr = new pkpy::NameDict(16, kTypeAttrLoadFactor);
|
||||||
}else if constexpr(std::is_same_v<T, DummyInstance>){
|
}else if constexpr(std::is_same_v<T, DummyInstance>){
|
||||||
_attr = new pkpy::NameDict(4, kInstAttrLoadFactor);
|
_attr = new pkpy::NameDict(4, kInstAttrLoadFactor);
|
||||||
|
}else if constexpr(std::is_same_v<T, pkpy::Function> || std::is_same_v<T, pkpy::NativeFunc>){
|
||||||
|
_attr = new pkpy::NameDict(4, kInstAttrLoadFactor);
|
||||||
}else{
|
}else{
|
||||||
_attr = nullptr;
|
_attr = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,7 @@ OPCODE(RE_RAISE)
|
|||||||
|
|
||||||
OPCODE(BUILD_INDEX)
|
OPCODE(BUILD_INDEX)
|
||||||
OPCODE(BUILD_ATTR)
|
OPCODE(BUILD_ATTR)
|
||||||
|
OPCODE(BUILD_ATTR_REF)
|
||||||
OPCODE(STORE_NAME)
|
OPCODE(STORE_NAME)
|
||||||
OPCODE(STORE_FUNCTION)
|
OPCODE(STORE_FUNCTION)
|
||||||
OPCODE(STORE_REF)
|
OPCODE(STORE_REF)
|
||||||
@ -83,5 +84,6 @@ OPCODE(INPLACE_BINARY_OP)
|
|||||||
OPCODE(INPLACE_BITWISE_OP)
|
OPCODE(INPLACE_BITWISE_OP)
|
||||||
|
|
||||||
OPCODE(SETUP_CLOSURE)
|
OPCODE(SETUP_CLOSURE)
|
||||||
|
OPCODE(SETUP_DECORATOR)
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -8,7 +8,7 @@ constexpr const char* kTokens[] = {
|
|||||||
"@error", "@eof", "@eol", "@sof",
|
"@error", "@eof", "@eol", "@sof",
|
||||||
".", ",", ":", ";", "#", "(", ")", "[", "]", "{", "}", "%", "::",
|
".", ",", ":", ";", "#", "(", ")", "[", "]", "{", "}", "%", "::",
|
||||||
"+", "-", "*", "/", "//", "**", "=", ">", "<", "...", "->",
|
"+", "-", "*", "/", "//", "**", "=", ">", "<", "...", "->",
|
||||||
"<<", ">>", "&", "|", "^", "?",
|
"<<", ">>", "&", "|", "^", "?", "@",
|
||||||
"==", "!=", ">=", "<=",
|
"==", "!=", ">=", "<=",
|
||||||
"+=", "-=", "*=", "/=", "//=", "%=", "&=", "|=", "^=",
|
"+=", "-=", "*=", "/=", "//=", "%=", "&=", "|=", "^=",
|
||||||
/** KW_BEGIN **/
|
/** KW_BEGIN **/
|
||||||
|
@ -70,6 +70,12 @@ void init_builtins(VM* _vm) {
|
|||||||
return vm->new_object(vm->tp_super, *self);
|
return vm->new_object(vm->tp_super, *self);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
_vm->bind_builtin_func<1>("id", [](VM* vm, pkpy::Args& args) {
|
||||||
|
const PyVar& obj = args[0];
|
||||||
|
if(obj.is_tagged()) return vm->PyInt((i64)0);
|
||||||
|
return vm->PyInt(obj.bits);
|
||||||
|
});
|
||||||
|
|
||||||
_vm->bind_builtin_func<1>("eval", [](VM* vm, pkpy::Args& args) {
|
_vm->bind_builtin_func<1>("eval", [](VM* vm, pkpy::Args& args) {
|
||||||
CodeObject_ code = vm->compile(vm->PyStr_AS_C(args[0]), "<eval>", EVAL_MODE);
|
CodeObject_ code = vm->compile(vm->PyStr_AS_C(args[0]), "<eval>", EVAL_MODE);
|
||||||
return vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals);
|
return vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals);
|
||||||
@ -776,6 +782,12 @@ void add_module_random(VM* vm){
|
|||||||
vm->_exec(code, mod);
|
vm->_exec(code, mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add_module_functools(VM* vm){
|
||||||
|
PyVar mod = vm->new_module("functools");
|
||||||
|
CodeObject_ code = vm->compile(kFuncToolsCode, "functools.py", EXEC_MODE);
|
||||||
|
vm->_exec(code, mod);
|
||||||
|
}
|
||||||
|
|
||||||
void VM::post_init(){
|
void VM::post_init(){
|
||||||
init_builtins(this);
|
init_builtins(this);
|
||||||
add_module_sys(this);
|
add_module_sys(this);
|
||||||
@ -787,6 +799,7 @@ void VM::post_init(){
|
|||||||
add_module_random(this);
|
add_module_random(this);
|
||||||
add_module_io(this);
|
add_module_io(this);
|
||||||
add_module_os(this);
|
add_module_os(this);
|
||||||
|
add_module_functools(this);
|
||||||
|
|
||||||
CodeObject_ code = compile(kBuiltinsCode, "<builtins>", EXEC_MODE);
|
CodeObject_ code = compile(kBuiltinsCode, "<builtins>", EXEC_MODE);
|
||||||
this->_exec(code, this->builtins);
|
this->_exec(code, this->builtins);
|
||||||
|
18
tests/_decorator.py
Normal file
18
tests/_decorator.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
def cache(f):
|
||||||
|
def wrapper(*args):
|
||||||
|
if not hasattr(f, 'cache'):
|
||||||
|
f.cache = {}
|
||||||
|
key = args
|
||||||
|
if key not in f.cache:
|
||||||
|
f.cache[key] = f(*args)
|
||||||
|
return f.cache[key]
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def fib(n):
|
||||||
|
if n < 2:
|
||||||
|
return n
|
||||||
|
return fib(n-1) + fib(n-2)
|
||||||
|
|
||||||
|
assert fib(32) == 2178309
|
Loading…
x
Reference in New Issue
Block a user