This commit is contained in:
blueloveTH 2024-07-18 11:48:32 +08:00 committed by blueloveTH
parent 31d095e3cc
commit 9d9674d171
12 changed files with 291 additions and 41 deletions

View File

@ -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_i64(c11_sbuf* self, int64_t);
void c11_sbuf__write_f64(c11_sbuf* self, double, int precision); void c11_sbuf__write_f64(c11_sbuf* self, double, int precision);
void c11_sbuf__write_char(c11_sbuf* self, char); 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_sv(c11_sbuf* self, c11_sv);
void c11_sbuf__write_cstr(c11_sbuf* self, const char*); void c11_sbuf__write_cstr(c11_sbuf* self, const char*);
void c11_sbuf__write_cstrn(c11_sbuf* self, const char*, int); void c11_sbuf__write_cstrn(c11_sbuf* self, const char*, int);

View File

@ -83,7 +83,7 @@ const char* py_name2str(py_Name);
py_Name py_namev(c11_sv name); py_Name py_namev(c11_sv name);
c11_sv py_name2sv(py_Name); c11_sv py_name2sv(py_Name);
bool py_ismagicname(py_Name); #define py_ismagicname(name) (name <= __missing__)
// opaque types // opaque types
void py_newdict(py_Ref); 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); void py_setupvalue(py_StackRef argv, const py_Ref val);
/// Gets the attribute of the object. /// Gets the attribute of the object.
/// 1: success, 0: not found, -1: error bool py_getattr(py_Ref self, py_Name name);
int py_getattr(const py_Ref self, py_Name name, py_Ref out);
/// Sets the attribute of the object. /// Sets the attribute of the object.
bool py_setattr(py_Ref self, py_Name name, const py_Ref val); bool py_setattr(py_Ref self, py_Name name, const py_Ref val);
/// Deletes the attribute of the object. /// Deletes the attribute of the object.

View File

@ -68,7 +68,6 @@ OPCODE(LOOP_BREAK)
OPCODE(JUMP_ABSOLUTE_TOP) OPCODE(JUMP_ABSOLUTE_TOP)
OPCODE(GOTO) OPCODE(GOTO)
/**************************/ /**************************/
OPCODE(FSTRING_EVAL)
OPCODE(REPR) OPCODE(REPR)
OPCODE(CALL) OPCODE(CALL)
OPCODE(CALL_VARGS) OPCODE(CALL_VARGS)
@ -108,6 +107,7 @@ OPCODE(RAISE_ASSERT)
OPCODE(RE_RAISE) OPCODE(RE_RAISE)
OPCODE(POP_EXCEPTION) OPCODE(POP_EXCEPTION)
/**************************/ /**************************/
OPCODE(FSTRING_EVAL)
OPCODE(FORMAT_STRING) OPCODE(FORMAT_STRING)
/**************************/ /**************************/
#endif #endif

View File

@ -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_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) { void c11_sbuf__write_int(c11_sbuf* self, int i) {
// len('-2147483648') == 11 // len('-2147483648') == 11
c11_vector__reserve(&self->data, self->data.count + 11 + 1); c11_vector__reserve(&self->data, self->data.count + 11 + 1);

View File

@ -62,4 +62,3 @@ c11_sv py_name2sv(py_Name index) {
return (c11_sv){p, strlen(p)}; return (c11_sv){p, strlen(p)};
} }
bool py_ismagicname(py_Name name) { return name <= __missing__; }

View File

@ -1126,7 +1126,7 @@ bool AttribExpr__emit_del(Expr* self_, Ctx* ctx) {
bool AttribExpr__emit_store(Expr* self_, Ctx* ctx) { bool AttribExpr__emit_store(Expr* self_, Ctx* ctx) {
AttribExpr* self = (AttribExpr*)self_; AttribExpr* self = (AttribExpr*)self_;
vtemit_(self->child, ctx); 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; return true;
} }

View File

@ -7,6 +7,7 @@
#include <stdbool.h> #include <stdbool.h>
static bool stack_unpack_sequence(pk_VM* self, uint16_t arg); static bool stack_unpack_sequence(pk_VM* self, uint16_t arg);
static bool format_object(py_Ref obj, c11_sv spec);
#define DISPATCH() \ #define DISPATCH() \
do { \ do { \
@ -231,22 +232,22 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
goto __ERROR; goto __ERROR;
} }
case OP_LOAD_ATTR: { case OP_LOAD_ATTR: {
int res = py_getattr(TOP(), byte.arg, TOP()); if(py_getattr(TOP(), byte.arg)) {
if(res == -1) goto __ERROR; py_assign(TOP(), py_retval());
if(!res) { } else {
AttributeError(TOP(), byte.arg);
goto __ERROR; goto __ERROR;
} }
DISPATCH(); DISPATCH();
} }
case OP_LOAD_CLASS_GLOBAL: { case OP_LOAD_CLASS_GLOBAL: {
py_Name name = byte.arg; py_Name name = byte.arg;
if(py_getattr(self->__curr_class, name, SP())) { py_Ref tmp = py_getdict(self->__curr_class, name);
SP()++; if(tmp) {
PUSH(tmp);
DISPATCH(); DISPATCH();
} }
// load global if attribute not found // load global if attribute not found
py_Ref tmp = py_getdict(&frame->module, name); tmp = py_getdict(&frame->module, name);
if(tmp) { if(tmp) {
PUSH(tmp); PUSH(tmp);
DISPATCH(); DISPATCH();
@ -267,9 +268,9 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
SP()++; SP()++;
} else { } else {
// fallback to getattr // fallback to getattr
int res = py_getattr(TOP(), byte.arg, TOP()); if(py_getattr(TOP(), byte.arg)) {
if(res != 1) { py_assign(TOP(), py_retval());
if(res == 0) { AttributeError(TOP(), byte.arg); } } else {
goto __ERROR; goto __ERROR;
} }
} }
@ -322,6 +323,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
DISPATCH(); DISPATCH();
} }
case OP_STORE_ATTR: { case OP_STORE_ATTR: {
// [val, a] -> a.b = val
if(!py_setattr(TOP(), byte.arg, SECOND())) goto __ERROR; if(!py_setattr(TOP(), byte.arg, SECOND())) goto __ERROR;
STACK_SHRINK(2); STACK_SHRINK(2);
DISPATCH(); DISPATCH();
@ -616,19 +618,20 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
POP(); POP();
DISPATCH_JUMP_ABSOLUTE(target); DISPATCH_JUMP_ABSOLUTE(target);
} }
// case OP_GOTO: { case OP_GOTO: {
// py_Name _name(byte.arg); int target = c11_smallmap_n2i__get(&frame->co->labels, byte.arg, -1);
// int target = c11_smallmap_n2i__get(&frame->co->labels, byte.arg, -1); if(target < 0) {
// if(target < 0) RuntimeError(_S("label ", _name.escape(), " not found")); RuntimeError("label '%n' not found", byte.arg);
// frame->prepare_jump_break(&s_data, target); goto __ERROR;
// DISPATCH_JUMP_ABSOLUTE(target) }
// } Frame__prepare_jump_break(frame, &self->stack, target);
/*****************************************/ DISPATCH_JUMP_ABSOLUTE(target);
case OP_FSTRING_EVAL: {
assert(false);
} }
/*****************************************/
case OP_REPR: { case OP_REPR: {
assert(false); if(!py_repr(TOP())) goto __ERROR;
py_assign(TOP(), py_retval());
DISPATCH();
} }
case OP_CALL: { case OP_CALL: {
pk_ManagedHeap__collect_if_needed(&self->heap); pk_ManagedHeap__collect_if_needed(&self->heap);
@ -678,7 +681,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
n = p - buf; n = p - buf;
kwargc += py_dict__len(kwargs) - 1; kwargc += py_dict__len(kwargs) - 1;
} else { } else {
TypeError("*kwargs must be a dict, got '%t'", kwargs->type); TypeError("**kwargs must be a dict, got '%t'", kwargs->type);
goto __ERROR; goto __ERROR;
} }
} }
@ -806,7 +809,8 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
base = py_totype(TOP()); base = py_totype(TOP());
} }
POP(); 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)); PUSH(py_tpobject(type));
self->__curr_class = TOP(); self->__curr_class = TOP();
DISPATCH(); DISPATCH();
@ -857,6 +861,22 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
} }
goto __ERROR; 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(); default: c11__unreachedable();
} }
@ -922,3 +942,130 @@ static bool stack_unpack_sequence(pk_VM* self, uint16_t arg) {
} }
return true; 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;
}

View File

@ -547,7 +547,7 @@ void pk_ManagedHeap__mark(pk_ManagedHeap* self) {
} }
void pk_print_stack(pk_VM* self, Frame* frame, Bytecode byte) { void pk_print_stack(pk_VM* self, Frame* frame, Bytecode byte) {
// return; return;
py_TValue* sp = self->stack.sp; py_TValue* sp = self->stack.sp;
c11_sbuf buf; c11_sbuf buf;

View File

@ -9,7 +9,7 @@ static bool _py_object__new__(int argc, py_Ref argv) {
if(!ti->is_python) { if(!ti->is_python) {
return TypeError("object.__new__(%t) is not safe, use %t.__new__()", cls, cls); 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; return true;
} }

View File

@ -77,11 +77,104 @@ int py_next(const py_Ref val) {
return vm->is_stopiteration ? 0 : -1; 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) { bool py_getitem(const py_Ref self, const py_Ref key) {
py_push(self); py_push(self);

View File

@ -83,7 +83,7 @@ static bool _py_str__hash__(int argc, py_Ref argv) {
static bool _py_str__len__(int argc, py_Ref argv) { static bool _py_str__len__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1); PY_CHECK_ARGC(1);
c11_string* self = py_touserdata(&argv[0]); 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; return true;
} }

View File

@ -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) { py_Ref py_getdict(const py_Ref self, py_Name name) {
assert(self && self->is_ptr); 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_Type* ud = py_touserdata(self);
py_Ref slot = py_tpmagic(*ud, name); py_Ref slot = py_tpmagic(*ud, name);
return py_isnil(slot) ? NULL : slot; 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) { void py_setdict(py_Ref self, py_Name name, const py_Ref val) {
assert(self && self->is_ptr); 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_Type* ud = py_touserdata(self);
*py_tpmagic(*ud, name) = *val; *py_tpmagic(*ud, name) = *val;
} }
pk_NameDict__set(PyObject__dict(self->_obj), name, *val);
} }
bool py_deldict(py_Ref self, py_Name name) { bool py_deldict(py_Ref self, py_Name name) {
assert(self && self->is_ptr); 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_Type* ud = py_touserdata(self);
py_newnil(py_tpmagic(*ud, name)); 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) { py_Ref py_getslot(const py_Ref self, int i) {