mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
...
This commit is contained in:
parent
31d095e3cc
commit
9d9674d171
@ -21,6 +21,7 @@ void c11_sbuf__write_int(c11_sbuf* self, int);
|
||||
void c11_sbuf__write_i64(c11_sbuf* self, int64_t);
|
||||
void c11_sbuf__write_f64(c11_sbuf* self, double, int precision);
|
||||
void c11_sbuf__write_char(c11_sbuf* self, char);
|
||||
void c11_sbuf__write_pad(c11_sbuf* self, int count, char pad);
|
||||
void c11_sbuf__write_sv(c11_sbuf* self, c11_sv);
|
||||
void c11_sbuf__write_cstr(c11_sbuf* self, const char*);
|
||||
void c11_sbuf__write_cstrn(c11_sbuf* self, const char*, int);
|
||||
|
@ -83,7 +83,7 @@ const char* py_name2str(py_Name);
|
||||
py_Name py_namev(c11_sv name);
|
||||
c11_sv py_name2sv(py_Name);
|
||||
|
||||
bool py_ismagicname(py_Name);
|
||||
#define py_ismagicname(name) (name <= __missing__)
|
||||
|
||||
// opaque types
|
||||
void py_newdict(py_Ref);
|
||||
@ -195,8 +195,7 @@ py_TmpRef py_getupvalue(py_StackRef argv);
|
||||
void py_setupvalue(py_StackRef argv, const py_Ref val);
|
||||
|
||||
/// Gets the attribute of the object.
|
||||
/// 1: success, 0: not found, -1: error
|
||||
int py_getattr(const py_Ref self, py_Name name, py_Ref out);
|
||||
bool py_getattr(py_Ref self, py_Name name);
|
||||
/// Sets the attribute of the object.
|
||||
bool py_setattr(py_Ref self, py_Name name, const py_Ref val);
|
||||
/// Deletes the attribute of the object.
|
||||
|
@ -68,7 +68,6 @@ OPCODE(LOOP_BREAK)
|
||||
OPCODE(JUMP_ABSOLUTE_TOP)
|
||||
OPCODE(GOTO)
|
||||
/**************************/
|
||||
OPCODE(FSTRING_EVAL)
|
||||
OPCODE(REPR)
|
||||
OPCODE(CALL)
|
||||
OPCODE(CALL_VARGS)
|
||||
@ -108,6 +107,7 @@ OPCODE(RAISE_ASSERT)
|
||||
OPCODE(RE_RAISE)
|
||||
OPCODE(POP_EXCEPTION)
|
||||
/**************************/
|
||||
OPCODE(FSTRING_EVAL)
|
||||
OPCODE(FORMAT_STRING)
|
||||
/**************************/
|
||||
#endif
|
||||
|
@ -20,6 +20,12 @@ void c11_sbuf__dtor(c11_sbuf* self) { c11_vector__dtor(&self->data); }
|
||||
|
||||
void c11_sbuf__write_char(c11_sbuf* self, char c) { c11_vector__push(char, &self->data, c); }
|
||||
|
||||
void c11_sbuf__write_pad(c11_sbuf* self, int count, char pad) {
|
||||
for(int i = 0; i < count; i++) {
|
||||
c11_sbuf__write_char(self, pad);
|
||||
}
|
||||
}
|
||||
|
||||
void c11_sbuf__write_int(c11_sbuf* self, int i) {
|
||||
// len('-2147483648') == 11
|
||||
c11_vector__reserve(&self->data, self->data.count + 11 + 1);
|
||||
|
@ -62,4 +62,3 @@ c11_sv py_name2sv(py_Name index) {
|
||||
return (c11_sv){p, strlen(p)};
|
||||
}
|
||||
|
||||
bool py_ismagicname(py_Name name) { return name <= __missing__; }
|
||||
|
@ -1126,7 +1126,7 @@ bool AttribExpr__emit_del(Expr* self_, Ctx* ctx) {
|
||||
bool AttribExpr__emit_store(Expr* self_, Ctx* ctx) {
|
||||
AttribExpr* self = (AttribExpr*)self_;
|
||||
vtemit_(self->child, ctx);
|
||||
Ctx__emit_(ctx, OP_STORE_ATTR, BC_NOARG, self->line);
|
||||
Ctx__emit_(ctx, OP_STORE_ATTR, self->name, self->line);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
static bool stack_unpack_sequence(pk_VM* self, uint16_t arg);
|
||||
static bool format_object(py_Ref obj, c11_sv spec);
|
||||
|
||||
#define DISPATCH() \
|
||||
do { \
|
||||
@ -231,22 +232,22 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
goto __ERROR;
|
||||
}
|
||||
case OP_LOAD_ATTR: {
|
||||
int res = py_getattr(TOP(), byte.arg, TOP());
|
||||
if(res == -1) goto __ERROR;
|
||||
if(!res) {
|
||||
AttributeError(TOP(), byte.arg);
|
||||
if(py_getattr(TOP(), byte.arg)) {
|
||||
py_assign(TOP(), py_retval());
|
||||
} else {
|
||||
goto __ERROR;
|
||||
}
|
||||
DISPATCH();
|
||||
}
|
||||
case OP_LOAD_CLASS_GLOBAL: {
|
||||
py_Name name = byte.arg;
|
||||
if(py_getattr(self->__curr_class, name, SP())) {
|
||||
SP()++;
|
||||
py_Ref tmp = py_getdict(self->__curr_class, name);
|
||||
if(tmp) {
|
||||
PUSH(tmp);
|
||||
DISPATCH();
|
||||
}
|
||||
// load global if attribute not found
|
||||
py_Ref tmp = py_getdict(&frame->module, name);
|
||||
tmp = py_getdict(&frame->module, name);
|
||||
if(tmp) {
|
||||
PUSH(tmp);
|
||||
DISPATCH();
|
||||
@ -267,9 +268,9 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
SP()++;
|
||||
} else {
|
||||
// fallback to getattr
|
||||
int res = py_getattr(TOP(), byte.arg, TOP());
|
||||
if(res != 1) {
|
||||
if(res == 0) { AttributeError(TOP(), byte.arg); }
|
||||
if(py_getattr(TOP(), byte.arg)) {
|
||||
py_assign(TOP(), py_retval());
|
||||
} else {
|
||||
goto __ERROR;
|
||||
}
|
||||
}
|
||||
@ -322,6 +323,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
DISPATCH();
|
||||
}
|
||||
case OP_STORE_ATTR: {
|
||||
// [val, a] -> a.b = val
|
||||
if(!py_setattr(TOP(), byte.arg, SECOND())) goto __ERROR;
|
||||
STACK_SHRINK(2);
|
||||
DISPATCH();
|
||||
@ -616,19 +618,20 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
POP();
|
||||
DISPATCH_JUMP_ABSOLUTE(target);
|
||||
}
|
||||
// case OP_GOTO: {
|
||||
// py_Name _name(byte.arg);
|
||||
// int target = c11_smallmap_n2i__get(&frame->co->labels, byte.arg, -1);
|
||||
// if(target < 0) RuntimeError(_S("label ", _name.escape(), " not found"));
|
||||
// frame->prepare_jump_break(&s_data, target);
|
||||
// DISPATCH_JUMP_ABSOLUTE(target)
|
||||
// }
|
||||
/*****************************************/
|
||||
case OP_FSTRING_EVAL: {
|
||||
assert(false);
|
||||
case OP_GOTO: {
|
||||
int target = c11_smallmap_n2i__get(&frame->co->labels, byte.arg, -1);
|
||||
if(target < 0) {
|
||||
RuntimeError("label '%n' not found", byte.arg);
|
||||
goto __ERROR;
|
||||
}
|
||||
Frame__prepare_jump_break(frame, &self->stack, target);
|
||||
DISPATCH_JUMP_ABSOLUTE(target);
|
||||
}
|
||||
/*****************************************/
|
||||
case OP_REPR: {
|
||||
assert(false);
|
||||
if(!py_repr(TOP())) goto __ERROR;
|
||||
py_assign(TOP(), py_retval());
|
||||
DISPATCH();
|
||||
}
|
||||
case OP_CALL: {
|
||||
pk_ManagedHeap__collect_if_needed(&self->heap);
|
||||
@ -678,7 +681,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
n = p - buf;
|
||||
kwargc += py_dict__len(kwargs) - 1;
|
||||
} else {
|
||||
TypeError("*kwargs must be a dict, got '%t'", kwargs->type);
|
||||
TypeError("**kwargs must be a dict, got '%t'", kwargs->type);
|
||||
goto __ERROR;
|
||||
}
|
||||
}
|
||||
@ -806,7 +809,8 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
base = py_totype(TOP());
|
||||
}
|
||||
POP();
|
||||
py_Type type = py_newtype(py_name2str(name), base, &frame->module, NULL);
|
||||
py_Type type =
|
||||
pk_newtype(py_name2str(name), base, &frame->module, NULL, true, false);
|
||||
PUSH(py_tpobject(type));
|
||||
self->__curr_class = TOP();
|
||||
DISPATCH();
|
||||
@ -857,6 +861,22 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
}
|
||||
goto __ERROR;
|
||||
}
|
||||
//////////////////
|
||||
case OP_FSTRING_EVAL: {
|
||||
py_TValue* tmp = c11__at(py_TValue, &frame->co->consts, byte.arg);
|
||||
const char* string = py_tostr(tmp);
|
||||
// TODO: optimize this
|
||||
if(!py_exec2(string, "<eval>", EVAL_MODE)) goto __ERROR;
|
||||
PUSH(py_retval());
|
||||
DISPATCH();
|
||||
}
|
||||
case OP_FORMAT_STRING: {
|
||||
py_Ref spec = c11__at(py_TValue, &frame->co->consts, byte.arg);
|
||||
bool ok = format_object(TOP(), py_tosv(spec));
|
||||
if(!ok) goto __ERROR;
|
||||
py_assign(TOP(), py_retval());
|
||||
DISPATCH();
|
||||
}
|
||||
default: c11__unreachedable();
|
||||
}
|
||||
|
||||
@ -922,3 +942,130 @@ static bool stack_unpack_sequence(pk_VM* self, uint16_t arg) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool format_object(py_Ref val, c11_sv spec) {
|
||||
if(spec.size == 0) return py_str(val);
|
||||
|
||||
char type;
|
||||
switch(spec.data[spec.size - 1]) {
|
||||
case 'f':
|
||||
case 'd':
|
||||
case 's':
|
||||
type = spec.data[spec.size - 1];
|
||||
spec.size--; // remove last char
|
||||
break;
|
||||
default: type = ' '; break;
|
||||
}
|
||||
|
||||
char pad_c = ' ';
|
||||
if(strchr("0-=*#@!~", spec.data[0])) {
|
||||
pad_c = spec.data[0];
|
||||
spec = c11_sv__slice(spec, 1);
|
||||
}
|
||||
|
||||
char align;
|
||||
if(spec.data[0] == '^') {
|
||||
align = '^';
|
||||
spec = c11_sv__slice(spec, 1);
|
||||
} else if(spec.data[0] == '>') {
|
||||
align = '>';
|
||||
spec = c11_sv__slice(spec, 1);
|
||||
} else if(spec.data[0] == '<') {
|
||||
align = '<';
|
||||
spec = c11_sv__slice(spec, 1);
|
||||
} else {
|
||||
align = (py_isint(val) || py_isfloat(val)) ? '>' : '<';
|
||||
}
|
||||
|
||||
int dot = c11_sv__index(spec, '.');
|
||||
py_i64 width, precision;
|
||||
|
||||
if(dot >= 0) {
|
||||
if(dot == 0) {
|
||||
// {.2f}
|
||||
width = -1;
|
||||
} else {
|
||||
// {10.2f}
|
||||
IntParsingResult res = c11__parse_uint(c11_sv__slice2(spec, 0, dot), &width, 10);
|
||||
if(res != IntParsing_SUCCESS) return ValueError("invalid format specifer");
|
||||
}
|
||||
IntParsingResult res = c11__parse_uint(c11_sv__slice(spec, dot + 1), &precision, 10);
|
||||
if(res != IntParsing_SUCCESS) return ValueError("invalid format specifer");
|
||||
} else {
|
||||
// {10s}
|
||||
IntParsingResult res = c11__parse_uint(spec, &width, 10);
|
||||
if(res != IntParsing_SUCCESS) return ValueError("invalid format specifer");
|
||||
precision = -1;
|
||||
}
|
||||
|
||||
if(type != 'f' && dot >= 0) {
|
||||
return ValueError("precision not allowed in the format specifier");
|
||||
}
|
||||
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
|
||||
if(type == 'f') {
|
||||
py_f64 x;
|
||||
if(!py_castfloat(val, &x)) {
|
||||
c11_sbuf__dtor(&buf);
|
||||
return false;
|
||||
}
|
||||
if(precision < 0) precision = 6;
|
||||
c11_sbuf__write_f64(&buf, x, precision);
|
||||
} else if(type == 'd') {
|
||||
if(!py_checkint(val)) {
|
||||
c11_sbuf__dtor(&buf);
|
||||
return false;
|
||||
}
|
||||
c11_sbuf__write_i64(&buf, py_toint(val));
|
||||
} else if(type == 's') {
|
||||
if(!py_checkstr(val)) {
|
||||
c11_sbuf__dtor(&buf);
|
||||
return false;
|
||||
}
|
||||
c11_sbuf__write_sv(&buf, py_tosv(val));
|
||||
} else {
|
||||
if(!py_str(val)) {
|
||||
c11_sbuf__dtor(&buf);
|
||||
return false;
|
||||
}
|
||||
c11_sbuf__write_sv(&buf, py_tosv(py_retval()));
|
||||
}
|
||||
|
||||
c11_string* body = c11_sbuf__submit(&buf);
|
||||
int length = c11_sv__u8_length(c11_string__sv(body));
|
||||
c11_sbuf__ctor(&buf); // reinit sbuf
|
||||
|
||||
if(width != -1 && width > length) {
|
||||
switch(align) {
|
||||
case '>': {
|
||||
c11_sbuf__write_pad(&buf, width - length, pad_c);
|
||||
c11_sbuf__write_sv(&buf, c11_string__sv(body));
|
||||
break;
|
||||
}
|
||||
case '<': {
|
||||
c11_sbuf__write_sv(&buf, c11_string__sv(body));
|
||||
c11_sbuf__write_pad(&buf, width - length, pad_c);
|
||||
break;
|
||||
}
|
||||
case '^': {
|
||||
int pad_left = (width - length) / 2;
|
||||
int pad_right = (width - length) - pad_left;
|
||||
c11_sbuf__write_pad(&buf, pad_left, pad_c);
|
||||
c11_sbuf__write_sv(&buf, c11_string__sv(body));
|
||||
c11_sbuf__write_pad(&buf, pad_right, pad_c);
|
||||
break;
|
||||
}
|
||||
default: c11__unreachedable();
|
||||
}
|
||||
} else {
|
||||
c11_sbuf__write_sv(&buf, c11_string__sv(body));
|
||||
}
|
||||
|
||||
c11_string__delete(body);
|
||||
c11_string* res = c11_sbuf__submit(&buf);
|
||||
py_newstrn(py_retval(), res->data, res->size);
|
||||
c11_string__delete(res);
|
||||
return true;
|
||||
}
|
@ -547,7 +547,7 @@ void pk_ManagedHeap__mark(pk_ManagedHeap* self) {
|
||||
}
|
||||
|
||||
void pk_print_stack(pk_VM* self, Frame* frame, Bytecode byte) {
|
||||
// return;
|
||||
return;
|
||||
|
||||
py_TValue* sp = self->stack.sp;
|
||||
c11_sbuf buf;
|
||||
|
@ -9,7 +9,7 @@ static bool _py_object__new__(int argc, py_Ref argv) {
|
||||
if(!ti->is_python) {
|
||||
return TypeError("object.__new__(%t) is not safe, use %t.__new__()", cls, cls);
|
||||
}
|
||||
py_newobject(py_retval(), cls, 0, 0);
|
||||
py_newobject(py_retval(), cls, -1, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -77,11 +77,104 @@ int py_next(const py_Ref val) {
|
||||
return vm->is_stopiteration ? 0 : -1;
|
||||
}
|
||||
|
||||
int py_getattr(const py_Ref self, py_Name name, py_Ref out) { return -1; }
|
||||
bool py_getattr(py_Ref self, py_Name name) {
|
||||
// https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance
|
||||
py_Type type = self->type;
|
||||
// handle super() proxy
|
||||
if(py_istype(self, tp_super)) {
|
||||
self = py_getslot(self, 0);
|
||||
type = *(py_Type*)py_touserdata(self);
|
||||
}
|
||||
|
||||
bool py_setattr(py_Ref self, py_Name name, const py_Ref val) { return false; }
|
||||
py_Ref cls_var = py_tpfindname(type, name);
|
||||
if(cls_var) {
|
||||
// handle descriptor
|
||||
if(py_istype(cls_var, tp_property)) {
|
||||
py_Ref getter = py_getslot(cls_var, 0);
|
||||
return py_call(getter, 1, self);
|
||||
}
|
||||
}
|
||||
// handle instance __dict__
|
||||
if(self->is_ptr && self->_obj->slots == -1) {
|
||||
if(!py_istype(self, tp_type)) {
|
||||
py_Ref res = py_getdict(self, name);
|
||||
if(res) {
|
||||
py_assign(py_retval(), res);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
py_Type* inner_type = py_touserdata(self);
|
||||
py_Ref res = py_tpfindname(*inner_type, name);
|
||||
if(res) {
|
||||
if(py_istype(res, tp_staticmethod)) {
|
||||
res = py_getslot(res, 0);
|
||||
} else if(py_istype(res, tp_classmethod)) {
|
||||
// TODO: make a closure
|
||||
assert(false);
|
||||
}
|
||||
py_assign(py_retval(), res);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool py_delattr(py_Ref self, py_Name name) { return false; }
|
||||
if(cls_var) {
|
||||
// bound method is non-data descriptor
|
||||
switch(cls_var->type) {
|
||||
case tp_function: assert(false);
|
||||
case tp_nativefunc: assert(false);
|
||||
case tp_staticmethod: assert(false);
|
||||
case tp_classmethod: assert(false);
|
||||
default: {
|
||||
py_assign(py_retval(), cls_var);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return AttributeError(self, name);
|
||||
}
|
||||
|
||||
bool py_setattr(py_Ref self, py_Name name, const py_Ref val) {
|
||||
py_Type type = self->type;
|
||||
// handle super() proxy
|
||||
if(py_istype(self, tp_super)) {
|
||||
self = py_getslot(self, 0);
|
||||
type = *(py_Type*)py_touserdata(self);
|
||||
}
|
||||
|
||||
py_Ref cls_var = py_tpfindname(type, name);
|
||||
if(cls_var) {
|
||||
// handle descriptor
|
||||
if(py_istype(cls_var, tp_property)) {
|
||||
py_Ref setter = py_getslot(cls_var, 1);
|
||||
if(!py_isnone(setter)) {
|
||||
py_push(setter);
|
||||
py_push(self);
|
||||
py_push(val);
|
||||
return py_vectorcall(1, 0);
|
||||
} else {
|
||||
return TypeError("readonly attribute: '%n'", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handle instance __dict__
|
||||
if(self->is_ptr && self->_obj->slots == -1) {
|
||||
py_setdict(self, name, val);
|
||||
return true;
|
||||
}
|
||||
|
||||
return TypeError("cannot set attribute");
|
||||
}
|
||||
|
||||
bool py_delattr(py_Ref self, py_Name name) {
|
||||
if(self->is_ptr && self->_obj->slots == -1) {
|
||||
if(py_deldict(self, name)) return true;
|
||||
return AttributeError(self, name);
|
||||
}
|
||||
return TypeError("cannot delete attribute");
|
||||
}
|
||||
|
||||
bool py_getitem(const py_Ref self, const py_Ref key) {
|
||||
py_push(self);
|
||||
|
@ -83,7 +83,7 @@ static bool _py_str__hash__(int argc, py_Ref argv) {
|
||||
static bool _py_str__len__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
c11_string* self = py_touserdata(&argv[0]);
|
||||
py_newint(py_retval(), self->size);
|
||||
py_newint(py_retval(), c11_sv__u8_length((c11_sv){self->data, self->size}));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -8,30 +8,35 @@ py_Ref py_reg(int i) { return pk_current_vm->reg + i; }
|
||||
|
||||
py_Ref py_getdict(const py_Ref self, py_Name name) {
|
||||
assert(self && self->is_ptr);
|
||||
if(self->type == tp_type && py_ismagicname(name)) {
|
||||
if(!py_ismagicname(name) || self->type != tp_type) {
|
||||
return pk_NameDict__try_get(PyObject__dict(self->_obj), name);
|
||||
} else {
|
||||
py_Type* ud = py_touserdata(self);
|
||||
py_Ref slot = py_tpmagic(*ud, name);
|
||||
return py_isnil(slot) ? NULL : slot;
|
||||
}
|
||||
return pk_NameDict__try_get(PyObject__dict(self->_obj), name);
|
||||
}
|
||||
|
||||
void py_setdict(py_Ref self, py_Name name, const py_Ref val) {
|
||||
assert(self && self->is_ptr);
|
||||
if(self->type == tp_type && py_ismagicname(name)) {
|
||||
if(!py_ismagicname(name) || self->type != tp_type) {
|
||||
pk_NameDict__set(PyObject__dict(self->_obj), name, *val);
|
||||
} else {
|
||||
py_Type* ud = py_touserdata(self);
|
||||
*py_tpmagic(*ud, name) = *val;
|
||||
}
|
||||
pk_NameDict__set(PyObject__dict(self->_obj), name, *val);
|
||||
}
|
||||
|
||||
bool py_deldict(py_Ref self, py_Name name) {
|
||||
assert(self && self->is_ptr);
|
||||
if(self->type == tp_type && py_ismagicname(name)) {
|
||||
if(!py_ismagicname(name) || self->type != tp_type) {
|
||||
return pk_NameDict__del(PyObject__dict(self->_obj), name);
|
||||
|
||||
} else {
|
||||
py_Type* ud = py_touserdata(self);
|
||||
py_newnil(py_tpmagic(*ud, name));
|
||||
return true;
|
||||
}
|
||||
return pk_NameDict__del(PyObject__dict(self->_obj), name);
|
||||
}
|
||||
|
||||
py_Ref py_getslot(const py_Ref self, int i) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user