mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
Compare commits
5 Commits
381e2d5b9a
...
4b4351e3fa
Author | SHA1 | Date | |
---|---|---|---|
|
4b4351e3fa | ||
|
c9cbecc401 | ||
|
403e3c9f0e | ||
|
7feb3047e9 | ||
|
6e1550213c |
@ -90,11 +90,14 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo
|
||||
const char* pk_opname(Opcode op);
|
||||
|
||||
// type registration
|
||||
void pk_object__register();
|
||||
void pk_number__register();
|
||||
py_Type pk_str__register();
|
||||
py_Type pk_bytes__register();
|
||||
py_Type pk_list__register();
|
||||
|
||||
py_TValue pk_builtins__register();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -208,12 +208,14 @@ bool py_binaryop(const py_Ref lhs, const py_Ref rhs, py_Name op, py_Name rop);
|
||||
void py_assign(py_Ref dst, const py_Ref src);
|
||||
|
||||
/************* Stack Operations *************/
|
||||
/// Returns a reference to the i-th object from the top of the stack.
|
||||
/// Return a reference to the i-th object from the top of the stack.
|
||||
/// i should be negative, e.g. (-1) means TOS.
|
||||
py_StackRef py_peek(int i);
|
||||
/// Pushes the object to the stack.
|
||||
/// Push the object to the stack.
|
||||
void py_push(const py_Ref src);
|
||||
/// Pops an object from the stack.
|
||||
/// Push a nil object to the stack.
|
||||
void py_pushnil();
|
||||
/// Pop an object from the stack.
|
||||
void py_pop();
|
||||
/// Shrink the stack by n.
|
||||
void py_shrink(int n);
|
||||
@ -291,8 +293,8 @@ bool py_callmethod(py_Ref self, py_Name, int argc, py_Ref argv);
|
||||
/// The stack remains unchanged after the operation.
|
||||
bool py_callmagic(py_Name name, int argc, py_Ref argv);
|
||||
|
||||
#define py_repr(self) py_callmagic(__repr__, 1, self)
|
||||
#define py_str(self) py_callmagic(__str__, 1, self)
|
||||
bool py_str(py_Ref val);
|
||||
bool py_repr(py_Ref val);
|
||||
|
||||
/// The return value of the most recent call.
|
||||
py_GlobalRef py_retval();
|
||||
|
@ -9,6 +9,7 @@ MAGIC_METHOD(__iter__)
|
||||
MAGIC_METHOD(__next__)
|
||||
MAGIC_METHOD(__neg__)
|
||||
MAGIC_METHOD(__invert__)
|
||||
MAGIC_METHOD(__bool__)
|
||||
// logical operators
|
||||
MAGIC_METHOD(__contains__)
|
||||
/////////////////////////////
|
||||
|
@ -272,24 +272,29 @@ ImagExpr* ImagExpr__new(int line, double value) {
|
||||
typedef struct LiteralExpr {
|
||||
EXPR_COMMON_HEADER
|
||||
const TokenValue* value;
|
||||
bool negated;
|
||||
} LiteralExpr;
|
||||
|
||||
void LiteralExpr__emit_(Expr* self_, Ctx* ctx) {
|
||||
LiteralExpr* self = (LiteralExpr*)self_;
|
||||
switch(self->value->index) {
|
||||
case TokenValue_I64: {
|
||||
int64_t val = self->value->_i64;
|
||||
py_i64 val = self->value->_i64;
|
||||
if(self->negated) val = -val;
|
||||
Ctx__emit_int(ctx, val, self->line);
|
||||
break;
|
||||
}
|
||||
case TokenValue_F64: {
|
||||
py_TValue value;
|
||||
py_newfloat(&value, self->value->_f64);
|
||||
py_f64 val = self->value->_f64;
|
||||
if(self->negated) val = -val;
|
||||
py_newfloat(&value, val);
|
||||
int index = Ctx__add_const(ctx, &value);
|
||||
Ctx__emit_(ctx, OP_LOAD_CONST, index, self->line);
|
||||
break;
|
||||
}
|
||||
case TokenValue_STR: {
|
||||
assert(!self->negated);
|
||||
c11_sv sv = c11_string__sv(self->value->_str);
|
||||
int index = Ctx__add_const_string(ctx, sv);
|
||||
Ctx__emit_(ctx, OP_LOAD_CONST, index, self->line);
|
||||
@ -308,6 +313,7 @@ LiteralExpr* LiteralExpr__new(int line, const TokenValue* value) {
|
||||
self->vt = &Vt;
|
||||
self->line = line;
|
||||
self->value = value;
|
||||
self->negated = false;
|
||||
return self;
|
||||
}
|
||||
|
||||
@ -330,9 +336,7 @@ void Literal0Expr__emit_(Expr* self_, Ctx* ctx) {
|
||||
}
|
||||
|
||||
Literal0Expr* Literal0Expr__new(int line, TokenIndex token) {
|
||||
const static ExprVt Vt = {.emit_ = Literal0Expr__emit_,
|
||||
.is_literal = true,
|
||||
.is_json_object = true};
|
||||
const static ExprVt Vt = {.emit_ = Literal0Expr__emit_, .is_json_object = true};
|
||||
static_assert_expr_size(Literal0Expr);
|
||||
Literal0Expr* self = PoolExpr_alloc();
|
||||
self->vt = &Vt;
|
||||
@ -875,7 +879,7 @@ static void _emit_compare(BinaryExpr* self, Ctx* ctx, c11_vector* jmps) {
|
||||
Ctx__emit_(ctx, OP_ROT_THREE, BC_NOARG, self->line); // [b, a, b]
|
||||
Ctx__emit_(ctx, OP_BINARY_OP, cmp_token2name(self->op), self->line);
|
||||
// [b, RES]
|
||||
int index = Ctx__emit_(ctx, OP_JUMP_IF_FALSE_OR_POP, BC_NOARG, self->line);
|
||||
int index = Ctx__emit_(ctx, OP_SHORTCUT_IF_FALSE_OR_POP, BC_NOARG, self->line);
|
||||
c11_vector__push(int, jmps, index);
|
||||
}
|
||||
|
||||
@ -949,10 +953,13 @@ static void BinaryExpr__emit_(Expr* self_, Ctx* ctx) {
|
||||
for(int i = 0; i < jmps.count; i++) {
|
||||
Ctx__patch_jump(ctx, c11__getitem(int, &jmps, i));
|
||||
}
|
||||
c11_vector__dtor(&jmps);
|
||||
}
|
||||
|
||||
BinaryExpr* BinaryExpr__new(int line, TokenIndex op, bool inplace) {
|
||||
const static ExprVt Vt = {.emit_ = BinaryExpr__emit_, .dtor = BinaryExpr__dtor};
|
||||
const static ExprVt Vt = {.emit_ = BinaryExpr__emit_,
|
||||
.dtor = BinaryExpr__dtor,
|
||||
.is_binary = true};
|
||||
static_assert_expr_size(BinaryExpr);
|
||||
BinaryExpr* self = PoolExpr_alloc();
|
||||
self->vt = &Vt;
|
||||
@ -1771,7 +1778,19 @@ static Error* exprUnaryOp(Compiler* self) {
|
||||
check(parse_expression(self, PREC_UNARY + 1, false));
|
||||
Expr* e = Ctx__s_popx(ctx());
|
||||
switch(op) {
|
||||
case TK_SUB: Ctx__s_push(ctx(), (Expr*)UnaryExpr__new(line, e, OP_UNARY_NEGATIVE)); break;
|
||||
case TK_SUB: {
|
||||
// constant fold
|
||||
if(e->vt->is_literal) {
|
||||
LiteralExpr* le = (LiteralExpr*)e;
|
||||
if(le->value->index == TokenValue_I64 || le->value->index == TokenValue_F64) {
|
||||
le->negated = true;
|
||||
}
|
||||
Ctx__s_push(ctx(), e);
|
||||
} else {
|
||||
Ctx__s_push(ctx(), (Expr*)UnaryExpr__new(line, e, OP_UNARY_NEGATIVE));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TK_INVERT: Ctx__s_push(ctx(), (Expr*)UnaryExpr__new(line, e, OP_UNARY_INVERT)); break;
|
||||
case TK_MUL: Ctx__s_push(ctx(), (Expr*)StarredExpr__new(line, e, 1)); break;
|
||||
case TK_POW: Ctx__s_push(ctx(), (Expr*)StarredExpr__new(line, e, 2)); break;
|
||||
|
@ -30,7 +30,11 @@ static bool stack_binaryop(pk_VM* self, py_Name op, py_Name rop);
|
||||
#define THIRD() (self->stack.sp - 3)
|
||||
#define FOURTH() (self->stack.sp - 4)
|
||||
#define STACK_SHRINK(n) (self->stack.sp -= n)
|
||||
#define PUSH(v) (*self->stack.sp++ = *v)
|
||||
#define PUSH(v) \
|
||||
do { \
|
||||
*self->stack.sp = *v; \
|
||||
self->stack.sp++; \
|
||||
} while(0)
|
||||
#define POP() (--self->stack.sp)
|
||||
#define POPX() (*--self->stack.sp)
|
||||
#define SP() (self->stack.sp)
|
||||
@ -52,7 +56,7 @@ static bool stack_binaryop(pk_VM* self, py_Name op, py_Name rop);
|
||||
PUSH(&self->last_retval); \
|
||||
goto __NEXT_FRAME; \
|
||||
case RES_ERROR: goto __ERROR; \
|
||||
default: c11__unreachedable(); \
|
||||
default: c11__unreachedable(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
@ -86,11 +90,35 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
for(py_Ref p = self->stack.begin; p != SP(); p++) {
|
||||
c11_sbuf__write_cstr(&buf, py_tpname(p->type));
|
||||
switch(p->type) {
|
||||
case 0: c11_sbuf__write_cstr(&buf, "nil"); break;
|
||||
case tp_int: c11_sbuf__write_i64(&buf, p->_i64); break;
|
||||
case tp_float: c11_sbuf__write_f64(&buf, p->_f64, -1); break;
|
||||
case tp_bool: c11_sbuf__write_cstr(&buf, p->_bool ? "True" : "False"); break;
|
||||
case tp_none_type: c11_sbuf__write_cstr(&buf, "None"); break;
|
||||
case tp_type: {
|
||||
pk_sprintf(&buf, "<class '%t'>", py_totype(p));
|
||||
break;
|
||||
}
|
||||
case tp_str: {
|
||||
int size;
|
||||
const char* data = py_tostrn(p, &size);
|
||||
pk_sprintf(&buf, "%q", (c11_sv){data, size});
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
pk_sprintf(&buf, "(%t)", p->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(p != TOP()) c11_sbuf__write_cstr(&buf, ", ");
|
||||
}
|
||||
c11_string* stack_str = c11_sbuf__submit(&buf);
|
||||
printf("L%-3d: %-25s %-6d [%s]\n", Frame__lineno(frame), pk_opname(byte.op), byte.arg, stack_str->data);
|
||||
printf("L%-3d: %-25s %-6d [%s]\n",
|
||||
Frame__lineno(frame),
|
||||
pk_opname(byte.op),
|
||||
byte.arg,
|
||||
stack_str->data);
|
||||
c11_string__delete(stack_str);
|
||||
#endif
|
||||
|
||||
@ -694,16 +722,9 @@ static bool stack_binaryop(pk_VM* self, py_Name op, py_Name rop) {
|
||||
// [a, b]
|
||||
py_Ref magic = py_tpfindmagic(SECOND()->type, op);
|
||||
if(magic) {
|
||||
if(magic->type == tp_nativefunc) {
|
||||
bool ok = magic->_cfunc(2, SECOND());
|
||||
if(!ok) return false;
|
||||
if(self->last_retval.type != tp_not_implemented_type) return true;
|
||||
} else {
|
||||
// standard call
|
||||
bool ok = py_call(magic, 2, SECOND());
|
||||
if(!ok) return false;
|
||||
if(self->last_retval.type != tp_not_implemented_type) return true;
|
||||
}
|
||||
bool ok = py_call(magic, 2, SECOND());
|
||||
if(!ok) return false;
|
||||
if(self->last_retval.type != tp_not_implemented_type) return true;
|
||||
}
|
||||
// try reverse operation
|
||||
if(rop) {
|
||||
@ -713,16 +734,9 @@ static bool stack_binaryop(pk_VM* self, py_Name op, py_Name rop) {
|
||||
*SECOND() = tmp;
|
||||
magic = py_tpfindmagic(SECOND()->type, rop);
|
||||
if(magic) {
|
||||
if(magic->type == tp_nativefunc) {
|
||||
bool ok = magic->_cfunc(2, SECOND());
|
||||
if(!ok) return false;
|
||||
if(self->last_retval.type != tp_not_implemented_type) return true;
|
||||
} else {
|
||||
// standard call
|
||||
bool ok = py_call(magic, 2, SECOND());
|
||||
if(!ok) return false;
|
||||
if(self->last_retval.type != tp_not_implemented_type) return true;
|
||||
}
|
||||
bool ok = py_call(magic, 2, SECOND());
|
||||
if(!ok) return false;
|
||||
if(self->last_retval.type != tp_not_implemented_type) return true;
|
||||
}
|
||||
}
|
||||
// eq/ne op never fails due to object.__eq__
|
||||
|
@ -56,12 +56,7 @@ void pk_TypeInfo__ctor(pk_TypeInfo* self,
|
||||
|
||||
void pk_TypeInfo__dtor(pk_TypeInfo* self) { c11_vector__dtor(&self->annotated_fields); }
|
||||
|
||||
static bool _py_object__new__(int argc, py_Ref argv) {
|
||||
assert(argc >= 1);
|
||||
py_Type cls = argv[0].type;
|
||||
py_newobject(py_retval(), cls, 0, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void pk_VM__ctor(pk_VM* self) {
|
||||
self->top_frame = NULL;
|
||||
@ -95,6 +90,7 @@ void pk_VM__ctor(pk_VM* self) {
|
||||
|
||||
validate(tp_object, pk_VM__new_type(self, "object", 0, NULL, true));
|
||||
validate(tp_type, pk_VM__new_type(self, "type", 1, NULL, false));
|
||||
pk_object__register();
|
||||
|
||||
validate(tp_int, pk_VM__new_type(self, "int", tp_object, NULL, false));
|
||||
validate(tp_float, pk_VM__new_type(self, "float", tp_object, NULL, false));
|
||||
@ -136,7 +132,7 @@ void pk_VM__ctor(pk_VM* self) {
|
||||
#undef validate
|
||||
|
||||
self->StopIteration = *py_tpobject(tp_stop_iteration);
|
||||
self->builtins = *py_newmodule("builtins", NULL);
|
||||
self->builtins = pk_builtins__register();
|
||||
|
||||
/* Setup Public Builtin Types */
|
||||
py_Type public_types[] = {tp_object,
|
||||
@ -166,10 +162,6 @@ void pk_VM__ctor(pk_VM* self) {
|
||||
py_newnotimplemented(&tmp);
|
||||
py_setdict(&self->builtins, py_name("NotImplemented"), &tmp);
|
||||
|
||||
/* Do Buildin Bindings*/
|
||||
// object.__new__
|
||||
py_bindmagic(tp_object, __new__, _py_object__new__);
|
||||
|
||||
self->main = *py_newmodule("__main__", NULL);
|
||||
}
|
||||
|
||||
|
@ -50,3 +50,29 @@ py_Ref py_newmodule(const char* name, const char* package) {
|
||||
py_poptmp(2);
|
||||
return py_getmodule(name);
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
|
||||
static bool _py_builtins__repr(int argc, py_Ref argv){
|
||||
PY_CHECK_ARGC(1);
|
||||
return py_repr(argv);
|
||||
}
|
||||
|
||||
static bool _py_builtins__exit(int argc, py_Ref argv){
|
||||
int code = 0;
|
||||
if(argc > 1) return TypeError("exit() takes at most 1 argument");
|
||||
if(argc == 1){
|
||||
PY_CHECK_ARG_TYPE(0, tp_int);
|
||||
code = py_toint(argv);
|
||||
}
|
||||
// return py_exception("SystemExit", "%d", code);
|
||||
exit(code);
|
||||
return false;
|
||||
}
|
||||
|
||||
py_TValue pk_builtins__register(){
|
||||
py_Ref builtins = py_newmodule("builtins", NULL);
|
||||
py_bindnativefunc(builtins, "repr", _py_builtins__repr);
|
||||
py_bindnativefunc(builtins, "exit", _py_builtins__exit);
|
||||
return *builtins;
|
||||
}
|
@ -7,12 +7,12 @@
|
||||
static bool _py_int##name(int argc, py_Ref argv) { \
|
||||
PY_CHECK_ARGC(2); \
|
||||
if(py_isint(&argv[1])) { \
|
||||
int64_t lhs = py_toint(&argv[0]); \
|
||||
int64_t rhs = py_toint(&argv[1]); \
|
||||
py_i64 lhs = py_toint(&argv[0]); \
|
||||
py_i64 rhs = py_toint(&argv[1]); \
|
||||
rint(py_retval(), lhs op rhs); \
|
||||
} else if(py_isfloat(&argv[1])) { \
|
||||
int64_t lhs = py_toint(&argv[0]); \
|
||||
double rhs = py_tofloat(&argv[1]); \
|
||||
py_i64 lhs = py_toint(&argv[0]); \
|
||||
py_f64 rhs = py_tofloat(&argv[1]); \
|
||||
rfloat(py_retval(), lhs op rhs); \
|
||||
} else { \
|
||||
py_newnotimplemented(py_retval()); \
|
||||
@ -21,8 +21,8 @@
|
||||
} \
|
||||
static bool _py_float##name(int argc, py_Ref argv) { \
|
||||
PY_CHECK_ARGC(2); \
|
||||
double lhs = py_tofloat(&argv[0]); \
|
||||
double rhs; \
|
||||
py_f64 lhs = py_tofloat(&argv[0]); \
|
||||
py_f64 rhs; \
|
||||
if(py_castfloat(&argv[1], &rhs)) { \
|
||||
rfloat(py_retval(), lhs op rhs); \
|
||||
} else { \
|
||||
@ -36,7 +36,7 @@ DEF_NUM_BINARY_OP(__sub__, -, py_newint, py_newfloat)
|
||||
DEF_NUM_BINARY_OP(__mul__, *, py_newint, py_newfloat)
|
||||
|
||||
DEF_NUM_BINARY_OP(__eq__, ==, py_newbool, py_newbool)
|
||||
DEF_NUM_BINARY_OP(__ne__, ==, py_newbool, py_newbool)
|
||||
DEF_NUM_BINARY_OP(__ne__, !=, py_newbool, py_newbool)
|
||||
DEF_NUM_BINARY_OP(__lt__, <, py_newbool, py_newbool)
|
||||
DEF_NUM_BINARY_OP(__le__, <=, py_newbool, py_newbool)
|
||||
DEF_NUM_BINARY_OP(__gt__, >, py_newbool, py_newbool)
|
||||
@ -46,22 +46,22 @@ DEF_NUM_BINARY_OP(__ge__, >=, py_newbool, py_newbool)
|
||||
|
||||
static bool _py_int__neg__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
int64_t val = py_toint(&argv[0]);
|
||||
py_i64 val = py_toint(&argv[0]);
|
||||
py_newint(py_retval(), -val);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_float__neg__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
double val = py_tofloat(&argv[0]);
|
||||
py_f64 val = py_tofloat(&argv[0]);
|
||||
py_newfloat(py_retval(), -val);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_int__truediv__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
int64_t lhs = py_toint(&argv[0]);
|
||||
double rhs;
|
||||
py_i64 lhs = py_toint(&argv[0]);
|
||||
py_f64 rhs;
|
||||
if(py_castfloat(&argv[1], &rhs)) {
|
||||
py_newfloat(py_retval(), lhs / rhs);
|
||||
} else {
|
||||
@ -72,8 +72,8 @@ static bool _py_int__truediv__(int argc, py_Ref argv) {
|
||||
|
||||
static bool _py_float__truediv__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
double lhs = py_tofloat(&argv[0]);
|
||||
double rhs;
|
||||
py_f64 lhs = py_tofloat(&argv[0]);
|
||||
py_f64 rhs;
|
||||
if(py_castfloat(&argv[1], &rhs)) {
|
||||
py_newfloat(py_retval(), lhs / rhs);
|
||||
} else {
|
||||
@ -87,8 +87,8 @@ static bool _py_float__truediv__(int argc, py_Ref argv) {
|
||||
static bool _py_number__pow__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
if(py_isint(&argv[0]) && py_isint(&argv[1])) {
|
||||
int64_t lhs = py_toint(&argv[0]);
|
||||
int64_t rhs = py_toint(&argv[1]);
|
||||
py_i64 lhs = py_toint(&argv[0]);
|
||||
py_i64 rhs = py_toint(&argv[1]);
|
||||
if(rhs < 0) {
|
||||
if(lhs == 0) {
|
||||
return ZeroDivisionError("0.0 cannot be raised to a negative power");
|
||||
@ -97,7 +97,7 @@ static bool _py_number__pow__(int argc, py_Ref argv) {
|
||||
}
|
||||
} else {
|
||||
// rhs >= 0
|
||||
int64_t ret = 1;
|
||||
py_i64 ret = 1;
|
||||
while(true) {
|
||||
if(rhs & 1) ret *= lhs;
|
||||
rhs >>= 1;
|
||||
@ -107,7 +107,7 @@ static bool _py_number__pow__(int argc, py_Ref argv) {
|
||||
py_newint(py_retval(), ret);
|
||||
}
|
||||
} else {
|
||||
double lhs, rhs;
|
||||
py_f64 lhs, rhs;
|
||||
py_castfloat(&argv[0], &lhs);
|
||||
if(py_castfloat(&argv[1], &rhs)) {
|
||||
py_newfloat(py_retval(), pow(lhs, rhs));
|
||||
@ -120,9 +120,9 @@ static bool _py_number__pow__(int argc, py_Ref argv) {
|
||||
|
||||
static bool _py_int__floordiv__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
int64_t lhs = py_toint(&argv[0]);
|
||||
py_i64 lhs = py_toint(&argv[0]);
|
||||
if(py_isint(&argv[1])) {
|
||||
int64_t rhs = py_toint(&argv[1]);
|
||||
py_i64 rhs = py_toint(&argv[1]);
|
||||
if(rhs == 0) return -1;
|
||||
py_newint(py_retval(), lhs / rhs);
|
||||
} else {
|
||||
@ -133,9 +133,9 @@ static bool _py_int__floordiv__(int argc, py_Ref argv) {
|
||||
|
||||
static bool _py_int__mod__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
int64_t lhs = py_toint(&argv[0]);
|
||||
py_i64 lhs = py_toint(&argv[0]);
|
||||
if(py_isint(&argv[1])) {
|
||||
int64_t rhs = py_toint(&argv[1]);
|
||||
py_i64 rhs = py_toint(&argv[1]);
|
||||
if(rhs == 0) return ZeroDivisionError("integer division or modulo by zero");
|
||||
py_newint(py_retval(), lhs % rhs);
|
||||
} else {
|
||||
@ -146,14 +146,14 @@ static bool _py_int__mod__(int argc, py_Ref argv) {
|
||||
|
||||
static bool _py_int__invert__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
int64_t val = py_toint(&argv[0]);
|
||||
py_i64 val = py_toint(&argv[0]);
|
||||
py_newint(py_retval(), ~val);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_int__bit_length(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
int64_t x = py_toint(py_arg(0));
|
||||
py_i64 x = py_toint(py_arg(0));
|
||||
if(x < 0) x = -x;
|
||||
int bits = 0;
|
||||
while(x) {
|
||||
@ -167,9 +167,9 @@ static bool _py_int__bit_length(int argc, py_Ref argv) {
|
||||
#define DEF_INT_BITWISE_OP(name, op) \
|
||||
static bool _py_int##name(int argc, py_Ref argv) { \
|
||||
PY_CHECK_ARGC(2); \
|
||||
int64_t lhs = py_toint(&argv[0]); \
|
||||
py_i64 lhs = py_toint(&argv[0]); \
|
||||
if(py_isint(&argv[1])) { \
|
||||
int64_t rhs = py_toint(&argv[1]); \
|
||||
py_i64 rhs = py_toint(&argv[1]); \
|
||||
py_newint(py_retval(), lhs op rhs); \
|
||||
} else { \
|
||||
py_newnotimplemented(py_retval()); \
|
||||
@ -187,7 +187,7 @@ DEF_INT_BITWISE_OP(__rshift__, >>)
|
||||
|
||||
static bool _py_int__repr__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
int64_t val = py_toint(&argv[0]);
|
||||
py_i64 val = py_toint(&argv[0]);
|
||||
char buf[32];
|
||||
int size = snprintf(buf, sizeof(buf), "%lld", (long long)val);
|
||||
py_newstrn(py_retval(), buf, size);
|
||||
@ -196,7 +196,7 @@ static bool _py_int__repr__(int argc, py_Ref argv) {
|
||||
|
||||
static bool _py_float__repr__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
double val = py_tofloat(&argv[0]);
|
||||
py_f64 val = py_tofloat(&argv[0]);
|
||||
char buf[32];
|
||||
int size = snprintf(buf, sizeof(buf), "%f", val);
|
||||
py_newstrn(py_retval(), buf, size);
|
||||
@ -223,7 +223,7 @@ static py_i64 c11_8bytes__hash(union c11_8bytes u) {
|
||||
|
||||
static bool _py_int__hash__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
int64_t val = py_toint(&argv[0]);
|
||||
py_i64 val = py_toint(&argv[0]);
|
||||
union c11_8bytes u = {._i64 = val};
|
||||
py_newint(py_retval(), c11_8bytes__hash(u));
|
||||
return true;
|
||||
@ -231,7 +231,7 @@ static bool _py_int__hash__(int argc, py_Ref argv) {
|
||||
|
||||
static bool _py_float__hash__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
double val = py_tofloat(&argv[0]);
|
||||
py_f64 val = py_tofloat(&argv[0]);
|
||||
union c11_8bytes u = {._f64 = val};
|
||||
py_newint(py_retval(), c11_8bytes__hash(u));
|
||||
return true;
|
||||
@ -248,7 +248,7 @@ static bool _py_int__new__(int argc, py_Ref argv) {
|
||||
switch(argv[1].type) {
|
||||
case tp_float: {
|
||||
// int(1.1) == 1
|
||||
py_newint(py_retval(), (int64_t)py_tofloat(&argv[1]));
|
||||
py_newint(py_retval(), (py_i64)py_tofloat(&argv[1]));
|
||||
return true;
|
||||
}
|
||||
case tp_int: {
|
||||
@ -258,7 +258,7 @@ static bool _py_int__new__(int argc, py_Ref argv) {
|
||||
}
|
||||
case tp_bool: {
|
||||
// int(True) == 1
|
||||
py_newint(py_retval(), (int64_t)py_tobool(&argv[1]));
|
||||
py_newint(py_retval(), (py_i64)py_tobool(&argv[1]));
|
||||
return true;
|
||||
}
|
||||
case tp_str: break; // leave to the next block
|
||||
@ -340,7 +340,7 @@ static bool _py_float__new__(int argc, py_Ref argv) {
|
||||
}
|
||||
|
||||
// tp_bool
|
||||
static bool _py_bool__new__(int argc, py_Ref argv){
|
||||
static bool _py_bool__new__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
int res = py_bool(argv);
|
||||
if(res == -1) return false;
|
||||
@ -348,24 +348,24 @@ static bool _py_bool__new__(int argc, py_Ref argv){
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_bool__hash__(int argc, py_Ref argv){
|
||||
static bool _py_bool__hash__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
bool res = py_tobool(argv);
|
||||
py_newint(py_retval(), res);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_bool__repr__(int argc, py_Ref argv){
|
||||
static bool _py_bool__repr__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
bool res = py_tobool(argv);
|
||||
py_newstr(py_retval(), res ? "True" : "False");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_bool__eq__(int argc, py_Ref argv){
|
||||
static bool _py_bool__eq__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
bool lhs = py_tobool(&argv[0]);
|
||||
if(argv[1].type == tp_bool){
|
||||
if(argv[1].type == tp_bool) {
|
||||
bool rhs = py_tobool(&argv[1]);
|
||||
py_newbool(py_retval(), lhs == rhs);
|
||||
} else {
|
||||
@ -374,10 +374,10 @@ static bool _py_bool__eq__(int argc, py_Ref argv){
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_bool__ne__(int argc, py_Ref argv){
|
||||
static bool _py_bool__ne__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
bool lhs = py_tobool(&argv[0]);
|
||||
if(argv[1].type == tp_bool){
|
||||
if(argv[1].type == tp_bool) {
|
||||
bool rhs = py_tobool(&argv[1]);
|
||||
py_newbool(py_retval(), lhs != rhs);
|
||||
} else {
|
||||
|
37
src/public/py_object.c
Normal file
37
src/public/py_object.c
Normal file
@ -0,0 +1,37 @@
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
static bool _py_object__new__(int argc, py_Ref argv) {
|
||||
assert(argc >= 1);
|
||||
py_Type cls = argv[0].type;
|
||||
py_newobject(py_retval(), cls, 0, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_object__hash__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
assert(argv->is_ptr);
|
||||
py_newint(py_retval(), (py_i64)argv->_obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_object__eq__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
bool res = py_isidentical(py_arg(0), py_arg(1));
|
||||
py_newbool(py_retval(), res);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_object__ne__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
bool res = py_isidentical(py_arg(0), py_arg(1));
|
||||
py_newbool(py_retval(), !res);
|
||||
return true;
|
||||
}
|
||||
|
||||
void pk_object__register() {
|
||||
py_bindmagic(tp_object, __new__, _py_object__new__);
|
||||
py_bindmagic(tp_object, __hash__, _py_object__hash__);
|
||||
py_bindmagic(tp_object, __eq__, _py_object__eq__);
|
||||
py_bindmagic(tp_object, __ne__, _py_object__ne__);
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
|
||||
bool py_isidentical(const py_Ref lhs, const py_Ref rhs) {
|
||||
if(lhs->type != rhs->type) return false;
|
||||
switch(lhs->type){
|
||||
switch(lhs->type) {
|
||||
case tp_int: return lhs->_i64 == rhs->_i64;
|
||||
case tp_float: return lhs->_f64 == rhs->_f64;
|
||||
case tp_bool: return lhs->_bool == rhs->_bool;
|
||||
@ -17,9 +17,48 @@ bool py_isidentical(const py_Ref lhs, const py_Ref rhs) {
|
||||
}
|
||||
}
|
||||
|
||||
int py_bool(const py_Ref val) { return 1; }
|
||||
int py_bool(const py_Ref val) {
|
||||
switch(val->type) {
|
||||
case tp_bool: return val->_bool;
|
||||
case tp_int: return val->_i64 != 0;
|
||||
case tp_float: return val->_f64 != 0;
|
||||
case tp_none_type: return 0;
|
||||
default: {
|
||||
py_Ref tmp = py_tpfindmagic(val->type, __bool__);
|
||||
if(tmp) {
|
||||
bool ok = py_call(tmp, 1, val);
|
||||
if(!ok) return -1;
|
||||
return py_tobool(py_retval());
|
||||
} else {
|
||||
tmp = py_tpfindmagic(val->type, __len__);
|
||||
if(tmp) {
|
||||
bool ok = py_call(tmp, 1, val);
|
||||
if(!ok) return -1;
|
||||
return py_toint(py_retval());
|
||||
} else {
|
||||
return 1; // True
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool py_hash(const py_Ref val, int64_t* out) { return 0; }
|
||||
bool py_hash(const py_Ref val, int64_t* out) {
|
||||
py_Type t = val->type;
|
||||
pk_TypeInfo* types = (pk_TypeInfo*)pk_current_vm->types.data;
|
||||
do {
|
||||
py_Ref _hash = &types[t].magic[__hash__];
|
||||
py_Ref _eq = &types[t].magic[__eq__];
|
||||
if(!py_isnil(_hash) && !py_isnil(_eq)) {
|
||||
bool ok = py_call(_hash, 1, val);
|
||||
if(!ok) return false;
|
||||
*out = py_toint(py_retval());
|
||||
return true;
|
||||
}
|
||||
t = types[t].base;
|
||||
} while(t);
|
||||
return TypeError("unhashable type: '%t'", val->type);
|
||||
}
|
||||
|
||||
int py_getattr(const py_Ref self, py_Name name, py_Ref out) { return -1; }
|
||||
|
||||
@ -37,7 +76,7 @@ bool py_delitem(py_Ref self, const py_Ref key) { return -1; }
|
||||
int py_##name(const py_Ref lhs, const py_Ref rhs) { \
|
||||
bool ok = py_binaryop(lhs, rhs, op, rop); \
|
||||
if(!ok) return -1; \
|
||||
return py_tobool(py_retval()); \
|
||||
return py_tobool(py_retval()); \
|
||||
}
|
||||
|
||||
COMPARE_OP_IMPL(eq, __eq__, __eq__)
|
||||
|
@ -52,8 +52,15 @@ unsigned char* py_tobytes(const py_Ref self, int* size) {
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
static bool _py_str__new__(int argc, py_Ref argv) { return true; }
|
||||
static bool _py_str__new__(int argc, py_Ref argv) {
|
||||
assert(argc >= 1);
|
||||
if(argc == 1) {
|
||||
py_newstr(py_retval(), "");
|
||||
return true;
|
||||
}
|
||||
if(argc > 2) return TypeError("str() takes at most 1 argument");
|
||||
return py_str(py_arg(1));
|
||||
}
|
||||
|
||||
static bool _py_str__hash__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
@ -157,7 +164,7 @@ static bool _py_str__getitem__(int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#define DEF_STR_CMP_OP(op, f, condition) \
|
||||
#define DEF_STR_CMP_OP(op, __f, __cond) \
|
||||
static bool _py_str##op(int argc, py_Ref argv) { \
|
||||
PY_CHECK_ARGC(2); \
|
||||
c11_string* self = py_touserdata(&argv[0]); \
|
||||
@ -165,8 +172,8 @@ static bool _py_str__getitem__(int argc, py_Ref argv) {
|
||||
py_newnotimplemented(py_retval()); \
|
||||
} else { \
|
||||
c11_string* other = py_touserdata(&argv[1]); \
|
||||
int res = c11_sv__cmp(c11_string__sv(self), c11_string__sv(other)); \
|
||||
py_newbool(py_retval(), condition); \
|
||||
int res = __f(c11_string__sv(self), c11_string__sv(other)); \
|
||||
py_newbool(py_retval(), __cond); \
|
||||
} \
|
||||
return true; \
|
||||
}
|
||||
@ -281,3 +288,11 @@ py_Type pk_bytes__register() {
|
||||
// no need to dtor because the memory is controlled by the object
|
||||
return type;
|
||||
}
|
||||
|
||||
bool py_str(py_Ref val) {
|
||||
py_Ref tmp = py_tpfindmagic(val->type, __str__);
|
||||
if(!tmp) return py_repr(val);
|
||||
return py_call(tmp, 1, val);
|
||||
}
|
||||
|
||||
bool py_repr(py_Ref val) { return py_callmagic(__repr__, 1, val); }
|
@ -64,6 +64,11 @@ void py_push(const py_Ref src){
|
||||
*vm->stack.sp++ = *src;
|
||||
}
|
||||
|
||||
void py_pushnil(){
|
||||
pk_VM* vm = pk_current_vm;
|
||||
py_newnil(vm->stack.sp++);
|
||||
}
|
||||
|
||||
py_Ref py_pushtmp(){
|
||||
pk_VM* vm = pk_current_vm;
|
||||
py_newnil(vm->stack.sp++);
|
||||
|
@ -184,11 +184,22 @@ bool py_exec(const char* source) { return pk_VM__exec(pk_current_vm, source, "<e
|
||||
|
||||
bool py_eval(const char* source) { return pk_VM__exec(pk_current_vm, source, "<eval>", EVAL_MODE); }
|
||||
|
||||
bool py_exec2(const char* source, const char* filename, enum CompileMode mode){
|
||||
bool py_exec2(const char* source, const char* filename, enum CompileMode mode) {
|
||||
return pk_VM__exec(pk_current_vm, source, filename, mode);
|
||||
}
|
||||
|
||||
bool py_call(py_Ref f, int argc, py_Ref argv) { return -1; }
|
||||
bool py_call(py_Ref f, int argc, py_Ref argv) {
|
||||
if(f->type == tp_nativefunc) {
|
||||
return f->_cfunc(argc, argv);
|
||||
} else {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
py_push(f);
|
||||
py_pushnil();
|
||||
for(int i = 0; i < argc; i++)
|
||||
py_push(py_offset(argv, i));
|
||||
return pk_VM__vectorcall(vm, argc, 0, false) == RES_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
bool py_callmethod(py_Ref self, py_Name name, int argc, py_Ref argv) { return -1; }
|
||||
|
||||
@ -285,9 +296,6 @@ bool py_callmagic(py_Name name, int argc, py_Ref argv) {
|
||||
assert(argc >= 1);
|
||||
assert(py_ismagicname(name));
|
||||
py_Ref tmp = py_tpfindmagic(argv->type, name);
|
||||
if(!tmp){
|
||||
return AttributeError(argv, name);
|
||||
}
|
||||
if(tmp->type == tp_nativefunc) return tmp->_cfunc(argc, argv);
|
||||
if(!tmp) return AttributeError(argv, name);
|
||||
return py_call(tmp, argc, argv);
|
||||
}
|
||||
|
106
tests/01_int.py
106
tests/01_int.py
@ -103,71 +103,49 @@ assert ~0 == -1
|
||||
assert str(1) == '1'
|
||||
assert repr(1) == '1'
|
||||
|
||||
try:
|
||||
1 // 0
|
||||
exit(1)
|
||||
except ZeroDivisionError:
|
||||
pass
|
||||
|
||||
try:
|
||||
1 % 0
|
||||
exit(1)
|
||||
except ZeroDivisionError:
|
||||
pass
|
||||
|
||||
try:
|
||||
2**60 // 0
|
||||
exit(1)
|
||||
except ZeroDivisionError:
|
||||
pass
|
||||
|
||||
try:
|
||||
2**60 % 0
|
||||
exit(1)
|
||||
except ZeroDivisionError:
|
||||
pass
|
||||
|
||||
try:
|
||||
divmod(1, 0)
|
||||
exit(1)
|
||||
except ZeroDivisionError:
|
||||
pass
|
||||
|
||||
try:
|
||||
divmod(2**60, 0)
|
||||
exit(1)
|
||||
except ZeroDivisionError:
|
||||
pass
|
||||
|
||||
assert 1 < 2 < 3
|
||||
assert 4 > 3 >= 3
|
||||
assert not 1 < 2 > 3
|
||||
|
||||
try:
|
||||
x = eval("231231312312312312312312312312312312314354657553423345632")
|
||||
print(f"eval should fail, but got {x!r}")
|
||||
exit(1)
|
||||
except SyntaxError:
|
||||
pass
|
||||
# try:
|
||||
# 1 // 0
|
||||
# exit(1)
|
||||
# except ZeroDivisionError:
|
||||
# pass
|
||||
|
||||
assert int("-5") == -5
|
||||
assert int("-4") == -4
|
||||
assert int("-3") == -3
|
||||
assert int("-2") == -2
|
||||
assert int("-1") == -1
|
||||
assert int("0") == 0
|
||||
assert int("1") == 1
|
||||
assert int("2") == 2
|
||||
assert int("3") == 3
|
||||
assert int("4") == 4
|
||||
assert int("5") == 5
|
||||
assert int("6") == 6
|
||||
assert int("7") == 7
|
||||
assert int("8") == 8
|
||||
assert int("9") == 9
|
||||
assert int("10") == 10
|
||||
assert int("11") == 11
|
||||
assert int("12") == 12
|
||||
assert int("13") == 13
|
||||
assert int("14") == 14
|
||||
assert int("15") == 15
|
||||
assert int("16") == 16
|
||||
# try:
|
||||
# 1 % 0
|
||||
# exit(1)
|
||||
# except ZeroDivisionError:
|
||||
# pass
|
||||
|
||||
# try:
|
||||
# 2**60 // 0
|
||||
# exit(1)
|
||||
# except ZeroDivisionError:
|
||||
# pass
|
||||
|
||||
# try:
|
||||
# 2**60 % 0
|
||||
# exit(1)
|
||||
# except ZeroDivisionError:
|
||||
# pass
|
||||
|
||||
# try:
|
||||
# divmod(1, 0)
|
||||
# exit(1)
|
||||
# except ZeroDivisionError:
|
||||
# pass
|
||||
|
||||
# try:
|
||||
# divmod(2**60, 0)
|
||||
# exit(1)
|
||||
# except ZeroDivisionError:
|
||||
# pass
|
||||
|
||||
# try:
|
||||
# x = eval("231231312312312312312312312312312312314354657553423345632")
|
||||
# print(f"eval should fail, but got {x!r}")
|
||||
# exit(1)
|
||||
# except SyntaxError:
|
||||
# pass
|
Loading…
x
Reference in New Issue
Block a user