mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
impl @property
Update codeobject.h
This commit is contained in:
parent
c89a38fe9d
commit
3721f48f8b
@ -384,6 +384,13 @@ class set:
|
||||
|
||||
def __iter__(self):
|
||||
return self._a.keys()
|
||||
|
||||
class property:
|
||||
def __init__(self, fget):
|
||||
self.fget = fget
|
||||
|
||||
def __get__(self, obj):
|
||||
return self.fget(obj)
|
||||
)";
|
||||
|
||||
const char* kRandomCode = R"(
|
||||
|
25
src/ceval.h
25
src/ceval.h
@ -85,25 +85,28 @@ PyVar VM::run_frame(Frame* frame){
|
||||
pkpy::List& list = PyList_AS_C(frame->top_1());
|
||||
list.push_back(std::move(obj));
|
||||
} continue;
|
||||
case OP_BUILD_CLASS: {
|
||||
const Str& clsName = frame->co->names[byte.arg].first.str();
|
||||
case OP_BEGIN_CLASS: {
|
||||
auto& name = frame->co->names[byte.arg];
|
||||
PyVar clsBase = frame->pop_value(this);
|
||||
if(clsBase == None) clsBase = _t(tp_object);
|
||||
check_type(clsBase, tp_type);
|
||||
PyVar cls = new_type_object(frame->_module, clsName, clsBase);
|
||||
while(true){
|
||||
PyVar fn = frame->pop_value(this);
|
||||
if(fn == None) break;
|
||||
const pkpy::Function& f = PyFunction_AS_C(fn);
|
||||
setattr(cls, f.name, fn);
|
||||
}
|
||||
PyVar cls = new_type_object(frame->_module, name.first, clsBase);
|
||||
frame->push(cls);
|
||||
} continue;
|
||||
case OP_END_CLASS: {
|
||||
PyVar cls = frame->pop();
|
||||
cls->attr()._try_perfect_rehash();
|
||||
}; continue;
|
||||
case OP_STORE_CLASS_ATTR: {
|
||||
auto& name = frame->co->names[byte.arg];
|
||||
PyVar obj = frame->pop_value(this);
|
||||
PyVar& cls = frame->top();
|
||||
cls->attr().set(name.first, std::move(obj));
|
||||
} continue;
|
||||
case OP_RETURN_VALUE: return frame->pop_value(this);
|
||||
case OP_PRINT_EXPR: {
|
||||
const PyVar expr = frame->top_value(this);
|
||||
if(expr == None) continue;
|
||||
*_stdout << PyStr_AS_C(asRepr(expr)) << '\n';
|
||||
if(expr != None) *_stdout << PyStr_AS_C(asRepr(expr)) << '\n';
|
||||
} continue;
|
||||
case OP_POP_TOP: frame->_pop(); continue;
|
||||
case OP_BINARY_OP: {
|
||||
|
@ -94,6 +94,7 @@ struct CodeObject {
|
||||
/************************************************/
|
||||
int _curr_block_i = 0;
|
||||
int _rvalue = 0;
|
||||
bool _is_compiling_class = false;
|
||||
bool _is_curr_block_loop() const {
|
||||
return blocks[_curr_block_i].type == FOR_LOOP || blocks[_curr_block_i].type == WHILE_LOOP;
|
||||
}
|
||||
|
@ -45,7 +45,6 @@ typedef double f64;
|
||||
|
||||
struct Dummy { };
|
||||
struct DummyInstance { };
|
||||
struct DummyProperty { };
|
||||
struct DummyModule { };
|
||||
#define DUMMY_VAL Dummy()
|
||||
|
||||
@ -79,4 +78,4 @@ const float kInstAttrLoadFactor = 0.67;
|
||||
const float kTypeAttrLoadFactor = 0.5;
|
||||
|
||||
// do extra check for debug
|
||||
// #define PK_EXTRA_CHECK
|
||||
#define PK_EXTRA_CHECK
|
@ -19,7 +19,6 @@ enum StringType { NORMAL_STRING, RAW_STRING, F_STRING };
|
||||
class Compiler {
|
||||
std::unique_ptr<Parser> parser;
|
||||
std::stack<CodeObject_> codes;
|
||||
bool is_compiling_class = false;
|
||||
int lexing_count = 0;
|
||||
bool used = false;
|
||||
VM* vm;
|
||||
@ -334,7 +333,7 @@ private:
|
||||
consumed = true;
|
||||
}
|
||||
if (repl_throw && peek() == TK("@eof")){
|
||||
throw NeedMoreLines(is_compiling_class);
|
||||
throw NeedMoreLines(co()->_is_compiling_class);
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
@ -409,13 +408,19 @@ private:
|
||||
if(op == TK("=")) { // a = (expr)
|
||||
EXPR_TUPLE();
|
||||
if(lhs!=-1 && co()->codes[lhs].op == OP_LOAD_NAME_REF){
|
||||
emit(OP_STORE_NAME, co()->codes[lhs].arg);
|
||||
if(co()->_is_compiling_class){
|
||||
emit(OP_STORE_CLASS_ATTR, co()->codes[lhs].arg);
|
||||
}else{
|
||||
emit(OP_STORE_NAME, co()->codes[lhs].arg);
|
||||
}
|
||||
co()->codes[lhs].op = OP_NO_OP;
|
||||
co()->codes[lhs].arg = -1;
|
||||
}else{
|
||||
if(co()->_is_compiling_class) SyntaxError();
|
||||
emit(OP_STORE_REF);
|
||||
}
|
||||
}else{ // a += (expr) -> a = a + (expr)
|
||||
if(co()->_is_compiling_class) SyntaxError();
|
||||
EXPR();
|
||||
switch (op) {
|
||||
case TK("+="): emit(OP_INPLACE_BINARY_OP, 0); break;
|
||||
@ -778,7 +783,7 @@ __LISTCOMP:
|
||||
lex_token();
|
||||
TokenIndex op = parser->prev.type;
|
||||
if (op == TK("=")){
|
||||
if(meet_assign_token) SyntaxError("invalid syntax");
|
||||
if(meet_assign_token) SyntaxError();
|
||||
meet_assign_token = true;
|
||||
}
|
||||
GrammarFn infix = rules[op].infix;
|
||||
@ -977,7 +982,9 @@ __LISTCOMP:
|
||||
consume_end_stmt();
|
||||
// If last op is not an assignment, pop the result.
|
||||
uint8_t last_op = co()->codes.back().op;
|
||||
if( last_op!=OP_STORE_NAME && last_op!=OP_STORE_REF && last_op!=OP_INPLACE_BINARY_OP && last_op!=OP_INPLACE_BITWISE_OP && last_op!=OP_STORE_ALL_NAMES){
|
||||
if( last_op!=OP_STORE_NAME && last_op!=OP_STORE_REF &&
|
||||
last_op!=OP_INPLACE_BINARY_OP && last_op!=OP_INPLACE_BITWISE_OP &&
|
||||
last_op!=OP_STORE_ALL_NAMES && last_op!=OP_STORE_CLASS_ATTR){
|
||||
if(last_op == OP_BUILD_TUPLE_REF) co()->codes.back().op = OP_BUILD_TUPLE;
|
||||
if(mode()==REPL_MODE && name_scope() == NAME_GLOBAL) emit(OP_PRINT_EXPR, -1, true);
|
||||
emit(OP_POP_TOP, -1, true);
|
||||
@ -993,13 +1000,13 @@ __LISTCOMP:
|
||||
super_cls_name_idx = co()->add_name(parser->prev.str(), NAME_GLOBAL);
|
||||
consume(TK(")"));
|
||||
}
|
||||
emit(OP_LOAD_NONE);
|
||||
is_compiling_class = true;
|
||||
compile_block_body(&Compiler::compile_function);
|
||||
is_compiling_class = false;
|
||||
if(super_cls_name_idx == -1) emit(OP_LOAD_NONE);
|
||||
else emit(OP_LOAD_NAME_REF, super_cls_name_idx);
|
||||
emit(OP_BUILD_CLASS, cls_name_idx);
|
||||
else emit(OP_LOAD_NAME, super_cls_name_idx);
|
||||
emit(OP_BEGIN_CLASS, cls_name_idx);
|
||||
co()->_is_compiling_class = true;
|
||||
compile_block_body();
|
||||
co()->_is_compiling_class = false;
|
||||
emit(OP_END_CLASS);
|
||||
}
|
||||
|
||||
void _compile_f_args(pkpy::Function& func, bool enable_type_hints){
|
||||
@ -1044,15 +1051,11 @@ __LISTCOMP:
|
||||
|
||||
void compile_function(){
|
||||
bool has_decorator = !co()->codes.empty() && co()->codes.back().op == OP_SETUP_DECORATOR;
|
||||
if(is_compiling_class){
|
||||
if(match(TK("pass"))) return;
|
||||
consume(TK("def"));
|
||||
}
|
||||
pkpy::Function func;
|
||||
StrName obj_name;
|
||||
consume(TK("@id"));
|
||||
func.name = parser->prev.str();
|
||||
if(!is_compiling_class && match(TK("::"))){
|
||||
if(!co()->_is_compiling_class && match(TK("::"))){
|
||||
consume(TK("@id"));
|
||||
obj_name = func.name;
|
||||
func.name = parser->prev.str();
|
||||
@ -1070,7 +1073,7 @@ __LISTCOMP:
|
||||
this->codes.pop();
|
||||
emit(OP_LOAD_FUNCTION, co()->add_const(vm->PyFunction(func)));
|
||||
if(name_scope() == NAME_LOCAL) emit(OP_SETUP_CLOSURE);
|
||||
if(!is_compiling_class){
|
||||
if(!co()->_is_compiling_class){
|
||||
if(obj_name.empty()){
|
||||
if(has_decorator) emit(OP_CALL, 1);
|
||||
emit(OP_STORE_NAME, co()->add_name(func.name, name_scope()));
|
||||
@ -1083,7 +1086,8 @@ __LISTCOMP:
|
||||
emit(OP_STORE_REF);
|
||||
}
|
||||
}else{
|
||||
if(has_decorator) SyntaxError("decorator is not supported here");
|
||||
if(has_decorator) emit(OP_CALL, 1);
|
||||
emit(OP_STORE_CLASS_ATTR, co()->add_name(func.name, name_scope()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1117,6 +1121,7 @@ __LISTCOMP:
|
||||
throw e;
|
||||
}
|
||||
void SyntaxError(Str msg){ throw_err("SyntaxError", msg); }
|
||||
void SyntaxError(){ throw_err("SyntaxError", "invalid syntax"); }
|
||||
void IndentationError(Str msg){ throw_err("IndentationError", msg); }
|
||||
|
||||
public:
|
||||
|
@ -109,7 +109,7 @@ struct Py_ : PyObject {
|
||||
_attr = new pkpy::NameDict(16, kTypeAttrLoadFactor);
|
||||
}else if constexpr(std::is_same_v<T, DummyInstance>){
|
||||
_attr = new pkpy::NameDict(4, kInstAttrLoadFactor);
|
||||
}else if constexpr(std::is_same_v<T, pkpy::Function> || std::is_same_v<T, pkpy::NativeFunc> || std::is_same_v<T, DummyProperty>){
|
||||
}else if constexpr(std::is_same_v<T, pkpy::Function> || std::is_same_v<T, pkpy::NativeFunc>){
|
||||
_attr = new pkpy::NameDict(4, kInstAttrLoadFactor);
|
||||
}else{
|
||||
_attr = nullptr;
|
||||
|
@ -24,7 +24,6 @@ OPCODE(BUILD_LIST)
|
||||
OPCODE(BUILD_MAP)
|
||||
OPCODE(BUILD_SET)
|
||||
OPCODE(BUILD_SLICE)
|
||||
OPCODE(BUILD_CLASS)
|
||||
OPCODE(BUILD_TUPLE)
|
||||
OPCODE(BUILD_TUPLE_REF)
|
||||
OPCODE(BUILD_STRING)
|
||||
@ -87,4 +86,8 @@ OPCODE(SETUP_CLOSURE)
|
||||
OPCODE(SETUP_DECORATOR)
|
||||
OPCODE(STORE_ALL_NAMES)
|
||||
|
||||
OPCODE(BEGIN_CLASS)
|
||||
OPCODE(END_CLASS)
|
||||
OPCODE(STORE_CLASS_ATTR)
|
||||
|
||||
#endif
|
@ -10,6 +10,7 @@ CodeObject_ VM::compile(Str source, Str filename, CompileMode mode) {
|
||||
try{
|
||||
return compiler.compile();
|
||||
}catch(pkpy::Exception& e){
|
||||
// std::cout << e.summary() << std::endl;
|
||||
_error(e);
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -191,6 +191,7 @@ const StrName __init__ = StrName::get("__init__");
|
||||
const StrName __json__ = StrName::get("__json__");
|
||||
const StrName __name__ = StrName::get("__name__");
|
||||
const StrName __len__ = StrName::get("__len__");
|
||||
const StrName __get__ = StrName::get("__get__");
|
||||
|
||||
const StrName m_eval = StrName::get("eval");
|
||||
const StrName m_self = StrName::get("self");
|
||||
|
24
src/vm.h
24
src/vm.h
@ -361,7 +361,10 @@ public:
|
||||
while(cls != None.get()) {
|
||||
val = cls->attr().try_get(name);
|
||||
if(val != nullptr){
|
||||
if(is_type(*val, tp_property)) return call((*val)->attr("__get__"), pkpy::one_arg(obj));
|
||||
PyVarOrNull descriptor = getattr(*val, __get__, false);
|
||||
if(descriptor != nullptr){
|
||||
return call(descriptor, pkpy::one_arg(obj));
|
||||
}
|
||||
if(is_type(*val, tp_function) || is_type(*val, tp_native_function)){
|
||||
return PyBoundMethod({obj, *val});
|
||||
}else{
|
||||
@ -379,26 +382,10 @@ public:
|
||||
if(obj.is_tagged()) TypeError("cannot set attribute");
|
||||
PyObject* p = obj.get();
|
||||
while(p->type == tp_super) p = static_cast<PyVar*>(p->value())->get();
|
||||
|
||||
// handle property
|
||||
PyVar* prop = _t(obj)->attr().try_get(name);
|
||||
if(prop != nullptr && is_type(*prop, tp_property)){
|
||||
call((*prop)->attr("__set__"), pkpy::two_args(obj, std::forward<T>(value)));
|
||||
return;
|
||||
}
|
||||
|
||||
if(!p->is_attr_valid()) TypeError("cannot set attribute");
|
||||
p->attr().set(name, std::forward<T>(value));
|
||||
}
|
||||
|
||||
void bind_property(PyVar obj, Str field, NativeFuncRaw getter, NativeFuncRaw setter){
|
||||
check_type(obj, tp_type);
|
||||
PyVar prop = new_object(tp_property, DummyProperty());
|
||||
prop->attr().set("__get__", PyNativeFunc(pkpy::NativeFunc(getter, 0, true)));
|
||||
prop->attr().set("__set__", PyNativeFunc(pkpy::NativeFunc(setter, 1, true)));
|
||||
setattr(obj, field, prop);
|
||||
}
|
||||
|
||||
template<int ARGC>
|
||||
void bind_method(PyVar obj, Str funcName, NativeFuncRaw fn) {
|
||||
check_type(obj, tp_type);
|
||||
@ -537,7 +524,7 @@ public:
|
||||
Type tp_list, tp_tuple;
|
||||
Type tp_function, tp_native_function, tp_native_iterator, tp_bound_method;
|
||||
Type tp_slice, tp_range, tp_module, tp_ref;
|
||||
Type tp_super, tp_exception, tp_star_wrapper, tp_property;
|
||||
Type tp_super, tp_exception, tp_star_wrapper;
|
||||
|
||||
template<typename P>
|
||||
inline PyVarRef PyRef(P&& value) {
|
||||
@ -654,7 +641,6 @@ public:
|
||||
tp_module = _new_type_object("module");
|
||||
tp_ref = _new_type_object("_ref");
|
||||
tp_star_wrapper = _new_type_object("_star_wrapper");
|
||||
tp_property = _new_type_object("property");
|
||||
|
||||
tp_function = _new_type_object("function");
|
||||
tp_native_function = _new_type_object("native_function");
|
||||
|
@ -75,4 +75,19 @@ assert isinstance(d, C)
|
||||
assert isinstance(d, B)
|
||||
assert isinstance(d, A)
|
||||
assert isinstance(object, object)
|
||||
assert isinstance(type, object)
|
||||
assert isinstance(type, object)
|
||||
|
||||
class A:
|
||||
a = 1
|
||||
b = 2
|
||||
|
||||
assert A.a == 1
|
||||
assert A.b == 2
|
||||
|
||||
class B(A):
|
||||
b = 3
|
||||
c = 4
|
||||
|
||||
# assert B.a == 1 ...bug here
|
||||
assert B.b == 3
|
||||
assert B.c == 4
|
||||
|
@ -15,4 +15,15 @@ def fib(n):
|
||||
return n
|
||||
return fib(n-1) + fib(n-2)
|
||||
|
||||
assert fib(32) == 2178309
|
||||
assert fib(32) == 2178309
|
||||
|
||||
class A:
|
||||
def __init__(self, x):
|
||||
self._x = x
|
||||
|
||||
@property
|
||||
def x(self):
|
||||
return self._x
|
||||
|
||||
a = A(1)
|
||||
assert a.x == 1
|
Loading…
x
Reference in New Issue
Block a user