mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
Compare commits
7 Commits
8ae999ecdf
...
34916d7578
Author | SHA1 | Date | |
---|---|---|---|
|
34916d7578 | ||
|
c2944b7fd8 | ||
|
4569547161 | ||
|
68bc6ee269 | ||
|
3da176fbfb | ||
|
3a8613b7ff | ||
|
facd1c0ce6 |
@ -15,7 +15,8 @@ extern "C" {
|
||||
|
||||
#define PK_REGION(name) 1
|
||||
|
||||
#define PK_SLICE_LOOP(i, start, stop, step) for(int i = start; step > 0 ? i < stop : i > stop; i += step)
|
||||
#define PK_SLICE_LOOP(i, start, stop, step) \
|
||||
for(int i = start; step > 0 ? i < stop : i > stop; i += step)
|
||||
|
||||
// global constants
|
||||
#define PK_HEX_TABLE "0123456789abcdef"
|
||||
@ -23,17 +24,21 @@ extern "C" {
|
||||
extern const char* kPlatformStrings[];
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define PK_UNREACHABLE() __assume(0);
|
||||
#define c11__unreachedable() __assume(0)
|
||||
#else
|
||||
#define PK_UNREACHABLE() __builtin_unreachable();
|
||||
#define c11__unreachedable() __builtin_unreachable()
|
||||
#endif
|
||||
|
||||
#define PK_FATAL_ERROR(...) { fprintf(stderr, __VA_ARGS__); abort(); }
|
||||
#define PK_FATAL_ERROR(...) \
|
||||
do { \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
abort(); \
|
||||
} while(0)
|
||||
|
||||
#define PK_MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define PK_MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define c11__min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define c11__max(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
#define PK_ARRAY_COUNT(a) (sizeof(a) / sizeof(a[0]))
|
||||
#define c11__count_array(a) (sizeof(a) / sizeof(a[0]))
|
||||
|
||||
// NARGS
|
||||
#define PK_NARGS_SEQ(_1, _2, _3, _4, N, ...) N
|
||||
@ -47,7 +52,8 @@ typedef struct RefCounted {
|
||||
} RefCounted;
|
||||
|
||||
#define PK_INCREF(obj) (obj)->rc.count++
|
||||
#define PK_DECREF(obj) do { \
|
||||
#define PK_DECREF(obj) \
|
||||
do { \
|
||||
if(--(obj)->rc.count == 0) { \
|
||||
(obj)->rc.dtor(obj); \
|
||||
free(obj); \
|
||||
|
@ -87,7 +87,6 @@ c11_array c11_vector__submit(c11_vector* self);
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
// NOTE: here we do an extra NULL check for it to avoid UB
|
||||
#define c11__foreach(T, self, it) \
|
||||
for(T* it = (self)->data; it && it != (T*)(self)->data + (self)->count; it++)
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include "pocketpy/interpreter/gc.h"
|
||||
#include "pocketpy/interpreter/frame.h"
|
||||
@ -56,7 +57,6 @@ typedef struct pk_VM {
|
||||
py_TValue reg[8]; // users' registers
|
||||
|
||||
py_TValue __curr_class;
|
||||
py_TValue __cached_object_new;
|
||||
FuncDecl_ __dynamic_func_decl;
|
||||
py_TValue __vectorcall_buffer[PK_MAX_CO_VARNAMES];
|
||||
|
||||
@ -70,8 +70,6 @@ void pk_VM__dtor(pk_VM* self);
|
||||
void pk_VM__push_frame(pk_VM* self, Frame* frame);
|
||||
void pk_VM__pop_frame(pk_VM* self);
|
||||
|
||||
void pk_VM__init_builtins(pk_VM* self);
|
||||
|
||||
typedef enum pk_FrameResult {
|
||||
RES_RETURN,
|
||||
RES_CALL,
|
||||
@ -89,7 +87,10 @@ py_Type pk_VM__new_type(pk_VM* self,
|
||||
|
||||
pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bool opcall);
|
||||
|
||||
const char* pk_opname(Opcode op);
|
||||
|
||||
// type registration
|
||||
void pk_number__register();
|
||||
py_Type pk_str__register();
|
||||
py_Type pk_bytes__register();
|
||||
py_Type pk_list__register();
|
||||
|
@ -36,7 +36,7 @@ typedef struct py_TValue {
|
||||
static_assert(sizeof(py_CFunction) <= 8, "sizeof(py_CFunction) > 8");
|
||||
static_assert(sizeof(py_TValue) == 16, "sizeof(py_TValue) != 16");
|
||||
|
||||
extern py_TValue PY_NULL;
|
||||
extern py_TValue PY_NIL;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ unsigned char* py_newbytes(py_Ref, int);
|
||||
void py_newnone(py_Ref);
|
||||
void py_newnotimplemented(py_Ref out);
|
||||
void py_newellipsis(py_Ref out);
|
||||
void py_newnull(py_Ref);
|
||||
void py_newnil(py_Ref);
|
||||
|
||||
/// Create a tuple with n UNINITIALIZED elements.
|
||||
/// You should initialize all elements before using it.
|
||||
@ -115,12 +115,13 @@ bool py_isinstance(const py_Ref obj, py_Type type);
|
||||
bool py_issubclass(py_Type derived, py_Type base);
|
||||
|
||||
/************* References *************/
|
||||
#define py_offset(p, i) (py_Ref)((char*)p + ((i) << 4))
|
||||
#define PY_CHECK_ARGC(n) \
|
||||
if(argc != n) return TypeError("expected %d arguments, got %d", n, argc)
|
||||
|
||||
#define TypeError(x) false
|
||||
#define PY_CHECK_ARG_TYPE(i, type) if(!py_checktype(py_arg(i), type)) return false
|
||||
|
||||
#define py_offset(p, i) (py_Ref)((char*)p + ((i) << 4))
|
||||
#define py_arg(i) py_offset(argv, i)
|
||||
#define py_checkargc(n) \
|
||||
if(argc != n) return TypeError()
|
||||
|
||||
py_GlobalRef py_tpmagic(py_Type type, py_Name name);
|
||||
#define py_bindmagic(type, __magic__, f) py_newnativefunc(py_tpmagic((type), __magic__), (f))
|
||||
@ -157,17 +158,14 @@ py_TmpRef py_getupvalue(py_StackRef argv);
|
||||
void py_setupvalue(py_StackRef argv, const py_Ref val);
|
||||
|
||||
/// Gets the attribute of the object.
|
||||
bool py_getattr(const py_Ref self, py_Name name, py_Ref out);
|
||||
/// Gets the unbound method of the object.
|
||||
bool py_getunboundmethod(const py_Ref self,
|
||||
py_Name name,
|
||||
bool fallback,
|
||||
py_Ref out,
|
||||
py_Ref out_self);
|
||||
/// 1: success, 0: not found, -1: error
|
||||
int py_getattr(const py_Ref self, py_Name name, py_Ref out);
|
||||
/// 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.
|
||||
bool py_delattr(py_Ref self, py_Name name);
|
||||
/// Gets the unbound method of the object.
|
||||
bool py_getunboundmethod(py_Ref self, py_Name name, py_Ref out, py_Ref out_self);
|
||||
|
||||
bool py_getitem(const py_Ref self, const py_Ref key, py_Ref out);
|
||||
bool py_setitem(py_Ref self, const py_Ref key, const py_Ref val);
|
||||
@ -226,11 +224,22 @@ py_TmpRef py_getmodule(const char* name);
|
||||
bool py_import(const char* name);
|
||||
|
||||
/************* Errors *************/
|
||||
bool py_exception(const char* name, const char* fmt, ...);
|
||||
/// Print the last error to the console.
|
||||
void py_printexc();
|
||||
/// Format the last error to a string.
|
||||
void py_formatexc(char* out);
|
||||
|
||||
#define KeyError(q) py_exception("KeyError", "'%q'", (q))
|
||||
#define NameError(n) py_exception("NameError", "name '%n' is not defined", (n))
|
||||
#define TypeError(...) py_exception("TypeError", __VA_ARGS__)
|
||||
#define ValueError(...) py_exception("ValueError", __VA_ARGS__)
|
||||
#define IndexError(...) py_exception("IndexError", __VA_ARGS__)
|
||||
#define AttributeError(self, n) \
|
||||
py_exception("AttributeError", "'%t' object has no attribute '%n'", (self)->type, (n))
|
||||
#define UnboundLocalError(n) \
|
||||
py_exception("UnboundLocalError", "local variable '%n' referenced before assignment", (n))
|
||||
|
||||
/************* Operators *************/
|
||||
/// Equivalent to `bool(val)`.
|
||||
/// Returns 1 if `val` is truthy, otherwise 0.
|
||||
@ -275,7 +284,7 @@ bool py_callmagic(py_Name name, int argc, py_Ref argv);
|
||||
/// The return value of the most recent call.
|
||||
py_GlobalRef py_retval();
|
||||
|
||||
#define py_isnull(self) ((self)->type == 0)
|
||||
#define py_isnil(self) ((self)->type == 0)
|
||||
|
||||
/* tuple */
|
||||
|
||||
@ -301,6 +310,10 @@ pk_TypeInfo* pk_tpinfo(const py_Ref self);
|
||||
/// Return the reference or NULL if not found.
|
||||
py_GlobalRef py_tpfindmagic(py_Type, py_Name name);
|
||||
|
||||
/// Search the name from the given type to the base type.
|
||||
/// Return the reference or NULL if not found.
|
||||
py_GlobalRef py_tpfindname(py_Type, py_Name name);
|
||||
|
||||
/// Get the type object of the given type.
|
||||
py_GlobalRef py_tpobject(py_Type type);
|
||||
|
||||
@ -333,28 +346,28 @@ enum py_MagicNames {
|
||||
|
||||
enum py_PredefinedTypes {
|
||||
tp_object = 1,
|
||||
tp_type,
|
||||
tp_type, // py_Type
|
||||
tp_int,
|
||||
tp_float,
|
||||
tp_bool,
|
||||
tp_str,
|
||||
tp_list,
|
||||
tp_tuple,
|
||||
tp_slice,
|
||||
tp_list, // c11_vector
|
||||
tp_tuple, // N slots
|
||||
tp_slice, // 3 slots (start, stop, step)
|
||||
tp_range,
|
||||
tp_module,
|
||||
tp_function,
|
||||
tp_nativefunc,
|
||||
tp_bound_method,
|
||||
tp_super,
|
||||
tp_super, // 1 slot + py_Type
|
||||
tp_exception,
|
||||
tp_bytes,
|
||||
tp_mappingproxy,
|
||||
tp_dict,
|
||||
tp_property,
|
||||
tp_property, // 2 slots (getter + setter)
|
||||
tp_star_wrapper,
|
||||
tp_staticmethod,
|
||||
tp_classmethod,
|
||||
tp_staticmethod, // 1 slot
|
||||
tp_classmethod, // 1 slot
|
||||
tp_none_type,
|
||||
tp_not_implemented_type,
|
||||
tp_ellipsis,
|
||||
@ -365,3 +378,13 @@ enum py_PredefinedTypes {
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Some notes:
|
||||
|
||||
## Macros
|
||||
1. Function macros are partial functions. They can be used as normal expressions. Use the same naming convention as functions.
|
||||
2. Snippet macros are `do {...} while(0)` blocks. They cannot be used as expressions. Use `UPPER_CASE` naming convention.
|
||||
3. Constant macros are used for global constants. Use `UPPER_CASE` or k-prefix naming convention.
|
||||
*/
|
@ -142,7 +142,7 @@ c11_string* c11_sbuf__submit(c11_sbuf* self) {
|
||||
}
|
||||
|
||||
void pk_vsprintf(c11_sbuf* ss, const char* fmt, va_list args) {
|
||||
while(fmt) {
|
||||
while(*fmt) {
|
||||
char c = *fmt;
|
||||
if(c != '%') {
|
||||
c11_sbuf__write_char(ss, c);
|
||||
|
@ -197,14 +197,14 @@ int c11__byte_index_to_unicode(const char* data, int n) {
|
||||
//////////////
|
||||
|
||||
int c11_sv__cmp(c11_sv self, c11_sv other) {
|
||||
int res = strncmp(self.data, other.data, PK_MIN(self.size, other.size));
|
||||
int res = strncmp(self.data, other.data, c11__min(self.size, other.size));
|
||||
if(res != 0) return res;
|
||||
return self.size - other.size;
|
||||
}
|
||||
|
||||
int c11_sv__cmp2(c11_sv self, const char* other) {
|
||||
int size = strlen(other);
|
||||
int res = strncmp(self.data, other, PK_MIN(self.size, size));
|
||||
int res = strncmp(self.data, other, c11__min(self.size, size));
|
||||
if(res != 0) return res;
|
||||
return self.size - size;
|
||||
}
|
||||
@ -241,14 +241,14 @@ int c11__u8_header(unsigned char c, bool suppress) {
|
||||
if((c & 0b11111000) == 0b11110000) return 4;
|
||||
if((c & 0b11111100) == 0b11111000) return 5;
|
||||
if((c & 0b11111110) == 0b11111100) return 6;
|
||||
if(!suppress) PK_FATAL_ERROR("invalid utf8 char\n")
|
||||
if(!suppress) PK_FATAL_ERROR("invalid utf8 char\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
IntParsingResult c11__parse_uint(c11_sv text, int64_t* out, int base) {
|
||||
*out = 0;
|
||||
|
||||
c11_sv prefix = {.data = text.data, .size = PK_MIN(2, text.size)};
|
||||
c11_sv prefix = {.data = text.data, .size = c11__min(2, text.size)};
|
||||
if(base == -1) {
|
||||
if(c11__sveq(prefix, "0b"))
|
||||
base = 2;
|
||||
|
@ -31,16 +31,14 @@ void py_Name__finalize() {
|
||||
c11_vector__dtor(&_r_interned);
|
||||
}
|
||||
|
||||
py_Name py_name(const char* name) {
|
||||
return py_name2((c11_sv){name, strlen(name)});
|
||||
}
|
||||
py_Name py_name(const char* name) { return py_name2((c11_sv){name, strlen(name)}); }
|
||||
|
||||
py_Name py_name2(c11_sv name) {
|
||||
// TODO: PK_GLOBAL_SCOPE_LOCK()
|
||||
uint16_t index = c11_smallmap_s2n__get(&_interned, name, 0);
|
||||
if(index != 0) return index;
|
||||
// generate new index
|
||||
if(_interned.count > 65530) { PK_FATAL_ERROR("py_Name index overflow\n"); }
|
||||
if(_interned.count > 65530) PK_FATAL_ERROR("py_Name index overflow\n");
|
||||
// NOTE: we must allocate the string in the heap so iterators are not invalidated
|
||||
char* p = malloc(name.size + 1);
|
||||
memcpy(p, name.data, name.size);
|
||||
@ -64,8 +62,4 @@ c11_sv py_name2sv(py_Name index) {
|
||||
return (c11_sv){p, strlen(p)};
|
||||
}
|
||||
|
||||
|
||||
bool py_ismagicname(py_Name name){
|
||||
return name <= __missing__;
|
||||
}
|
||||
|
||||
bool py_ismagicname(py_Name name) { return name <= __missing__; }
|
||||
|
@ -70,29 +70,29 @@ typedef struct Ctx {
|
||||
|
||||
typedef struct Expr Expr;
|
||||
|
||||
void Ctx__ctor(Ctx* self, CodeObject* co, FuncDecl* func, int level);
|
||||
void Ctx__dtor(Ctx* self);
|
||||
int Ctx__get_loop(Ctx* self);
|
||||
CodeBlock* Ctx__enter_block(Ctx* self, CodeBlockType type);
|
||||
void Ctx__exit_block(Ctx* self);
|
||||
int Ctx__emit_(Ctx* self, Opcode opcode, uint16_t arg, int line);
|
||||
int Ctx__emit_virtual(Ctx* self, Opcode opcode, uint16_t arg, int line, bool virtual);
|
||||
void Ctx__revert_last_emit_(Ctx* self);
|
||||
int Ctx__emit_int(Ctx* self, int64_t value, int line);
|
||||
void Ctx__patch_jump(Ctx* self, int index);
|
||||
bool Ctx__add_label(Ctx* self, py_Name name);
|
||||
int Ctx__add_varname(Ctx* self, py_Name name);
|
||||
int Ctx__add_const(Ctx* self, py_Ref);
|
||||
int Ctx__add_const_string(Ctx* self, c11_sv);
|
||||
void Ctx__emit_store_name(Ctx* self, NameScope scope, py_Name name, int line);
|
||||
void Ctx__try_merge_for_iter_store(Ctx* self, int);
|
||||
void Ctx__s_emit_top(Ctx*); // emit top -> pop -> delete
|
||||
void Ctx__s_push(Ctx*, Expr*); // push
|
||||
Expr* Ctx__s_top(Ctx*); // top
|
||||
int Ctx__s_size(Ctx*); // size
|
||||
void Ctx__s_pop(Ctx*); // pop -> delete
|
||||
Expr* Ctx__s_popx(Ctx*); // pop move
|
||||
void Ctx__s_emit_decorators(Ctx*, int count);
|
||||
static void Ctx__ctor(Ctx* self, CodeObject* co, FuncDecl* func, int level);
|
||||
static void Ctx__dtor(Ctx* self);
|
||||
static int Ctx__get_loop(Ctx* self);
|
||||
static CodeBlock* Ctx__enter_block(Ctx* self, CodeBlockType type);
|
||||
static void Ctx__exit_block(Ctx* self);
|
||||
static int Ctx__emit_(Ctx* self, Opcode opcode, uint16_t arg, int line);
|
||||
static int Ctx__emit_virtual(Ctx* self, Opcode opcode, uint16_t arg, int line, bool virtual);
|
||||
static void Ctx__revert_last_emit_(Ctx* self);
|
||||
static int Ctx__emit_int(Ctx* self, int64_t value, int line);
|
||||
static void Ctx__patch_jump(Ctx* self, int index);
|
||||
static bool Ctx__add_label(Ctx* self, py_Name name);
|
||||
static int Ctx__add_varname(Ctx* self, py_Name name);
|
||||
static int Ctx__add_const(Ctx* self, py_Ref);
|
||||
static int Ctx__add_const_string(Ctx* self, c11_sv);
|
||||
static void Ctx__emit_store_name(Ctx* self, NameScope scope, py_Name name, int line);
|
||||
static void Ctx__try_merge_for_iter_store(Ctx* self, int);
|
||||
static void Ctx__s_emit_top(Ctx*); // emit top -> pop -> delete
|
||||
static void Ctx__s_push(Ctx*, Expr*); // push
|
||||
static Expr* Ctx__s_top(Ctx*); // top
|
||||
static int Ctx__s_size(Ctx*); // size
|
||||
static void Ctx__s_pop(Ctx*); // pop -> delete
|
||||
static Expr* Ctx__s_popx(Ctx*); // pop move
|
||||
static void Ctx__s_emit_decorators(Ctx*, int count);
|
||||
|
||||
/* expr.c */
|
||||
typedef struct NameExpr {
|
||||
@ -129,7 +129,7 @@ bool NameExpr__emit_del(Expr* self_, Ctx* ctx) {
|
||||
break;
|
||||
case NAME_GLOBAL: Ctx__emit_(ctx, OP_DELETE_GLOBAL, self->name, self->line); break;
|
||||
case NAME_GLOBAL_UNKNOWN: Ctx__emit_(ctx, OP_DELETE_NAME, self->name, self->line); break;
|
||||
default: PK_UNREACHABLE();
|
||||
default: c11__unreachedable();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -294,7 +294,7 @@ void LiteralExpr__emit_(Expr* self_, Ctx* ctx) {
|
||||
Ctx__emit_(ctx, OP_LOAD_CONST, index, self->line);
|
||||
break;
|
||||
}
|
||||
default: PK_UNREACHABLE();
|
||||
default: c11__unreachedable();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1076,6 +1076,11 @@ typedef struct AttribExpr {
|
||||
py_Name name;
|
||||
} AttribExpr;
|
||||
|
||||
void AttribExpr__dtor(Expr* self_) {
|
||||
AttribExpr* self = (AttribExpr*)self_;
|
||||
vtdelete(self->child);
|
||||
}
|
||||
|
||||
void AttribExpr__emit_(Expr* self_, Ctx* ctx) {
|
||||
AttribExpr* self = (AttribExpr*)self_;
|
||||
vtemit_(self->child, ctx);
|
||||
@ -1117,6 +1122,7 @@ AttribExpr* AttribExpr__new(int line, Expr* child, py_Name name) {
|
||||
.emit_store = AttribExpr__emit_store,
|
||||
.emit_inplace = AttribExpr__emit_inplace,
|
||||
.emit_istore = AttribExpr__emit_istore,
|
||||
.dtor = AttribExpr__dtor,
|
||||
.is_attrib = true};
|
||||
static_assert_expr_size(AttribExpr);
|
||||
AttribExpr* self = PoolExpr_alloc();
|
||||
@ -1202,7 +1208,7 @@ CallExpr* CallExpr__new(int line, Expr* callable) {
|
||||
}
|
||||
|
||||
/* context.c */
|
||||
void Ctx__ctor(Ctx* self, CodeObject* co, FuncDecl* func, int level) {
|
||||
static void Ctx__ctor(Ctx* self, CodeObject* co, FuncDecl* func, int level) {
|
||||
self->co = co;
|
||||
self->func = func;
|
||||
self->level = level;
|
||||
@ -1213,12 +1219,11 @@ void Ctx__ctor(Ctx* self, CodeObject* co, FuncDecl* func, int level) {
|
||||
c11_smallmap_s2n__ctor(&self->co_consts_string_dedup_map);
|
||||
}
|
||||
|
||||
void Ctx__dtor(Ctx* self) {
|
||||
static void Ctx__dtor(Ctx* self) {
|
||||
// clean the expr stack
|
||||
for(int i = 0; i < self->s_expr.count; i++) {
|
||||
vtdelete(c11__getitem(Expr*, &self->s_expr, i));
|
||||
}
|
||||
c11_vector__clear(&self->s_expr);
|
||||
c11_vector__dtor(&self->s_expr);
|
||||
c11_smallmap_n2i__dtor(&self->global_names);
|
||||
c11_smallmap_s2n__dtor(&self->co_consts_string_dedup_map);
|
||||
@ -1226,7 +1231,7 @@ void Ctx__dtor(Ctx* self) {
|
||||
|
||||
static bool is_small_int(int64_t value) { return value >= INT16_MIN && value <= INT16_MAX; }
|
||||
|
||||
int Ctx__get_loop(Ctx* self) {
|
||||
static int Ctx__get_loop(Ctx* self) {
|
||||
int index = self->curr_iblock;
|
||||
while(index >= 0) {
|
||||
CodeBlock* block = c11__at(CodeBlock, &self->co->blocks, index);
|
||||
@ -1237,14 +1242,14 @@ int Ctx__get_loop(Ctx* self) {
|
||||
return index;
|
||||
}
|
||||
|
||||
CodeBlock* Ctx__enter_block(Ctx* self, CodeBlockType type) {
|
||||
static CodeBlock* Ctx__enter_block(Ctx* self, CodeBlockType type) {
|
||||
CodeBlock block = {type, self->curr_iblock, self->co->codes.count, -1, -1};
|
||||
c11_vector__push(CodeBlock, &self->co->blocks, block);
|
||||
self->curr_iblock = self->co->blocks.count - 1;
|
||||
return c11__at(CodeBlock, &self->co->blocks, self->curr_iblock);
|
||||
}
|
||||
|
||||
void Ctx__exit_block(Ctx* self) {
|
||||
static void Ctx__exit_block(Ctx* self) {
|
||||
CodeBlock* block = c11__at(CodeBlock, &self->co->blocks, self->curr_iblock);
|
||||
CodeBlockType curr_type = block->type;
|
||||
block->end = self->co->codes.count;
|
||||
@ -1256,7 +1261,7 @@ void Ctx__exit_block(Ctx* self) {
|
||||
}
|
||||
}
|
||||
|
||||
void Ctx__s_emit_decorators(Ctx* self, int count) {
|
||||
static void Ctx__s_emit_decorators(Ctx* self, int count) {
|
||||
assert(Ctx__s_size(self) >= count);
|
||||
// [obj]
|
||||
for(int i = 0; i < count; i++) {
|
||||
@ -1270,7 +1275,7 @@ void Ctx__s_emit_decorators(Ctx* self, int count) {
|
||||
}
|
||||
}
|
||||
|
||||
int Ctx__emit_virtual(Ctx* self, Opcode opcode, uint16_t arg, int line, bool is_virtual) {
|
||||
static int Ctx__emit_virtual(Ctx* self, Opcode opcode, uint16_t arg, int line, bool is_virtual) {
|
||||
Bytecode bc = {(uint8_t)opcode, arg};
|
||||
BytecodeEx bcx = {line, is_virtual, self->curr_iblock};
|
||||
c11_vector__push(Bytecode, &self->co->codes, bc);
|
||||
@ -1281,16 +1286,16 @@ int Ctx__emit_virtual(Ctx* self, Opcode opcode, uint16_t arg, int line, bool is_
|
||||
return i;
|
||||
}
|
||||
|
||||
int Ctx__emit_(Ctx* self, Opcode opcode, uint16_t arg, int line) {
|
||||
static int Ctx__emit_(Ctx* self, Opcode opcode, uint16_t arg, int line) {
|
||||
return Ctx__emit_virtual(self, opcode, arg, line, false);
|
||||
}
|
||||
|
||||
void Ctx__revert_last_emit_(Ctx* self) {
|
||||
static void Ctx__revert_last_emit_(Ctx* self) {
|
||||
c11_vector__pop(&self->co->codes);
|
||||
c11_vector__pop(&self->co->codes_ex);
|
||||
}
|
||||
|
||||
void Ctx__try_merge_for_iter_store(Ctx* self, int i) {
|
||||
static void Ctx__try_merge_for_iter_store(Ctx* self, int i) {
|
||||
// [FOR_ITER, STORE_?, ]
|
||||
Bytecode* co_codes = (Bytecode*)self->co->codes.data;
|
||||
if(co_codes[i].op != OP_FOR_ITER) return;
|
||||
@ -1310,7 +1315,7 @@ void Ctx__try_merge_for_iter_store(Ctx* self, int i) {
|
||||
}
|
||||
}
|
||||
|
||||
int Ctx__emit_int(Ctx* self, int64_t value, int line) {
|
||||
static int Ctx__emit_int(Ctx* self, int64_t value, int line) {
|
||||
if(is_small_int(value)) {
|
||||
return Ctx__emit_(self, OP_LOAD_SMALL_INT, (uint16_t)value, line);
|
||||
} else {
|
||||
@ -1320,20 +1325,20 @@ int Ctx__emit_int(Ctx* self, int64_t value, int line) {
|
||||
}
|
||||
}
|
||||
|
||||
void Ctx__patch_jump(Ctx* self, int index) {
|
||||
static void Ctx__patch_jump(Ctx* self, int index) {
|
||||
Bytecode* co_codes = (Bytecode*)self->co->codes.data;
|
||||
int target = self->co->codes.count;
|
||||
Bytecode__set_signed_arg(&co_codes[index], target - index);
|
||||
}
|
||||
|
||||
bool Ctx__add_label(Ctx* self, py_Name name) {
|
||||
static bool Ctx__add_label(Ctx* self, py_Name name) {
|
||||
bool ok = c11_smallmap_n2i__contains(&self->co->labels, name);
|
||||
if(ok) return false;
|
||||
c11_smallmap_n2i__set(&self->co->labels, name, self->co->codes.count);
|
||||
return true;
|
||||
}
|
||||
|
||||
int Ctx__add_varname(Ctx* self, py_Name name) {
|
||||
static int Ctx__add_varname(Ctx* self, py_Name name) {
|
||||
// PK_MAX_CO_VARNAMES will be checked when pop_context(), not here
|
||||
int index = c11_smallmap_n2i__get(&self->co->varnames_inv, name, -1);
|
||||
if(index >= 0) return index;
|
||||
@ -1344,7 +1349,7 @@ int Ctx__add_varname(Ctx* self, py_Name name) {
|
||||
return index;
|
||||
}
|
||||
|
||||
int Ctx__add_const_string(Ctx* self, c11_sv key) {
|
||||
static int Ctx__add_const_string(Ctx* self, c11_sv key) {
|
||||
uint16_t* val = c11_smallmap_s2n__try_get(&self->co_consts_string_dedup_map, key);
|
||||
if(val) {
|
||||
return *val;
|
||||
@ -1360,49 +1365,50 @@ int Ctx__add_const_string(Ctx* self, c11_sv key) {
|
||||
}
|
||||
}
|
||||
|
||||
int Ctx__add_const(Ctx* self, py_Ref v) {
|
||||
static int Ctx__add_const(Ctx* self, py_Ref v) {
|
||||
assert(v->type != tp_str);
|
||||
c11_vector__push(py_TValue, &self->co->consts, *v);
|
||||
return self->co->consts.count - 1;
|
||||
}
|
||||
|
||||
void Ctx__emit_store_name(Ctx* self, NameScope scope, py_Name name, int line) {
|
||||
static void Ctx__emit_store_name(Ctx* self, NameScope scope, py_Name name, int line) {
|
||||
switch(scope) {
|
||||
case NAME_LOCAL: Ctx__emit_(self, OP_STORE_FAST, Ctx__add_varname(self, name), line); break;
|
||||
case NAME_GLOBAL: Ctx__emit_(self, OP_STORE_GLOBAL, name, line); break;
|
||||
case NAME_GLOBAL_UNKNOWN: Ctx__emit_(self, OP_STORE_NAME, name, line); break;
|
||||
default: PK_UNREACHABLE();
|
||||
default: c11__unreachedable();
|
||||
}
|
||||
}
|
||||
|
||||
// emit top -> pop -> delete
|
||||
void Ctx__s_emit_top(Ctx* self) {
|
||||
static void Ctx__s_emit_top(Ctx* self) {
|
||||
Expr* top = c11_vector__back(Expr*, &self->s_expr);
|
||||
vtemit_(top, self);
|
||||
c11_vector__pop(&self->s_expr);
|
||||
vtdelete(top);
|
||||
c11_vector__pop(&self->s_expr);
|
||||
}
|
||||
|
||||
// push
|
||||
void Ctx__s_push(Ctx* self, Expr* expr) { c11_vector__push(Expr*, &self->s_expr, expr); }
|
||||
static void Ctx__s_push(Ctx* self, Expr* expr) { c11_vector__push(Expr*, &self->s_expr, expr); }
|
||||
|
||||
// top
|
||||
Expr* Ctx__s_top(Ctx* self) { return c11_vector__back(Expr*, &self->s_expr); }
|
||||
static Expr* Ctx__s_top(Ctx* self) { return c11_vector__back(Expr*, &self->s_expr); }
|
||||
|
||||
// size
|
||||
int Ctx__s_size(Ctx* self) { return self->s_expr.count; }
|
||||
static int Ctx__s_size(Ctx* self) { return self->s_expr.count; }
|
||||
|
||||
// pop -> delete
|
||||
void Ctx__s_pop(Ctx* self) {
|
||||
vtdelete(c11_vector__back(Expr*, &self->s_expr));
|
||||
static void Ctx__s_pop(Ctx* self) {
|
||||
Expr* top = c11_vector__back(Expr*, &self->s_expr);
|
||||
vtdelete(top);
|
||||
c11_vector__pop(&self->s_expr);
|
||||
}
|
||||
|
||||
// pop move
|
||||
Expr* Ctx__s_popx(Ctx* self) {
|
||||
Expr* e = c11_vector__back(Expr*, &self->s_expr);
|
||||
static Expr* Ctx__s_popx(Ctx* self) {
|
||||
Expr* top = c11_vector__back(Expr*, &self->s_expr);
|
||||
c11_vector__pop(&self->s_expr);
|
||||
return e;
|
||||
return top;
|
||||
}
|
||||
|
||||
/* compiler.c */
|
||||
@ -2313,10 +2319,8 @@ Error* pk_compile(pk_SourceData_ src, CodeObject* out) {
|
||||
CodeObject__ctor(out, src, c11_string__sv(src->filename));
|
||||
err = Compiler__compile(&compiler, out);
|
||||
if(err) {
|
||||
// if error occurs, dispose the code object
|
||||
// dispose the code object if error occurs
|
||||
CodeObject__dtor(out);
|
||||
} else {
|
||||
assert(out->codes.count);
|
||||
}
|
||||
Compiler__dtor(&compiler);
|
||||
return err;
|
||||
|
@ -5,13 +5,6 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
int UnboundLocalError(py_Name name) { return -1; }
|
||||
|
||||
int NameError(py_Name name) { return -1; }
|
||||
|
||||
#define AttributeError(obj, name) false
|
||||
#define BinaryOptError(op) false
|
||||
|
||||
static bool stack_binaryop(pk_VM* self, py_Name op, py_Name rop);
|
||||
|
||||
#define DISPATCH() \
|
||||
@ -59,7 +52,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: PK_UNREACHABLE(); \
|
||||
default: c11__unreachedable(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
@ -89,6 +82,18 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
__NEXT_STEP:
|
||||
byte = *frame->ip;
|
||||
|
||||
#if 1
|
||||
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));
|
||||
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);
|
||||
c11_string__delete(stack_str);
|
||||
#endif
|
||||
|
||||
switch((Opcode)byte.op) {
|
||||
case OP_NO_OP: DISPATCH();
|
||||
/*****************************************/
|
||||
@ -127,7 +132,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
case OP_LOAD_TRUE: py_newbool(SP()++, true); DISPATCH();
|
||||
case OP_LOAD_FALSE: py_newbool(SP()++, false); DISPATCH();
|
||||
/*****************************************/
|
||||
case OP_LOAD_SMALL_INT: py_newint(SP()++, (int64_t)(int16_t)byte.arg); DISPATCH();
|
||||
case OP_LOAD_SMALL_INT: py_newint(SP()++, (int16_t)byte.arg); DISPATCH();
|
||||
/*****************************************/
|
||||
case OP_LOAD_ELLIPSIS: py_newellipsis(SP()++); DISPATCH();
|
||||
case OP_LOAD_FUNCTION: {
|
||||
@ -147,12 +152,12 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
// PUSH(obj);DISPATCH();
|
||||
}
|
||||
case OP_LOAD_NULL:
|
||||
py_newnull(SP()++);
|
||||
py_newnil(SP()++);
|
||||
DISPATCH();
|
||||
/*****************************************/
|
||||
case OP_LOAD_FAST: {
|
||||
PUSH(&frame->locals[byte.arg]);
|
||||
if(py_isnull(TOP())) {
|
||||
if(py_isnil(TOP())) {
|
||||
py_Name name = c11__getitem(uint16_t, &frame->co->varnames, byte.arg);
|
||||
UnboundLocalError(name);
|
||||
goto __ERROR;
|
||||
@ -163,7 +168,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
py_Name name = byte.arg;
|
||||
py_Ref tmp = Frame__f_locals_try_get(frame, name);
|
||||
if(tmp != NULL) {
|
||||
if(py_isnull(tmp)) {
|
||||
if(py_isnil(tmp)) {
|
||||
UnboundLocalError(name);
|
||||
goto __ERROR;
|
||||
}
|
||||
@ -252,9 +257,19 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
goto __ERROR;
|
||||
}
|
||||
case OP_LOAD_METHOD: {
|
||||
// `py_getunboundmethod` never fails on `fallback=true`
|
||||
py_getunboundmethod(TOP(), byte.arg, true, TOP(), SP());
|
||||
// [self]
|
||||
bool ok = py_getunboundmethod(TOP(), byte.arg, TOP(), SP());
|
||||
if(ok) {
|
||||
// [unbound, self]
|
||||
SP()++;
|
||||
} else {
|
||||
// fallback to getattr
|
||||
int res = py_getattr(TOP(), byte.arg, TOP());
|
||||
if(res != 1) {
|
||||
if(res == 0) { AttributeError(TOP(), byte.arg); }
|
||||
goto __ERROR;
|
||||
}
|
||||
}
|
||||
DISPATCH();
|
||||
}
|
||||
case OP_LOAD_SUBSCR: {
|
||||
@ -273,7 +288,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
}
|
||||
DISPATCH();
|
||||
}
|
||||
TypeError();
|
||||
TypeError("'%t' object is not subscriptable", SECOND()->type);
|
||||
goto __ERROR;
|
||||
}
|
||||
case OP_STORE_FAST: frame->locals[byte.arg] = POPX(); DISPATCH();
|
||||
@ -327,16 +342,17 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
}
|
||||
DISPATCH();
|
||||
}
|
||||
TypeError();
|
||||
TypeError("'%t' object does not support item assignment", SECOND()->type);
|
||||
goto __ERROR;
|
||||
}
|
||||
case OP_DELETE_FAST: {
|
||||
py_Ref tmp = &frame->locals[byte.arg];
|
||||
if(py_isnull(tmp)) {
|
||||
UnboundLocalError(c11__getitem(uint16_t, &frame->co->varnames, byte.arg));
|
||||
if(py_isnil(tmp)) {
|
||||
py_Name name = c11__getitem(py_Name, &frame->co->varnames, byte.arg);
|
||||
UnboundLocalError(name);
|
||||
goto __ERROR;
|
||||
}
|
||||
py_newnull(tmp);
|
||||
py_newnil(tmp);
|
||||
DISPATCH();
|
||||
}
|
||||
case OP_DELETE_NAME: {
|
||||
@ -344,7 +360,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
if(frame->function) {
|
||||
py_TValue* slot = Frame__f_locals_try_get(frame, name);
|
||||
if(slot) {
|
||||
py_newnull(slot);
|
||||
py_newnil(slot);
|
||||
} else {
|
||||
// Function& func = frame->_callable->as<Function>();
|
||||
// if(func.decl == __dynamic_func_decl) {
|
||||
@ -397,7 +413,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
}
|
||||
DISPATCH();
|
||||
}
|
||||
TypeError();
|
||||
TypeError("'%t' object does not support item deletion", SECOND()->type);
|
||||
goto __ERROR;
|
||||
}
|
||||
/*****************************************/
|
||||
@ -417,7 +433,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
assert(f != NULL);
|
||||
py_TValue tmp = *TOP();
|
||||
*TOP() = *f; // [complex]
|
||||
py_newnull(SP()++); // [complex, NULL]
|
||||
py_newnil(SP()++); // [complex, NULL]
|
||||
py_newint(SP()++, 0); // [complex, NULL, 0]
|
||||
*SP()++ = tmp; // [complex, NULL, 0, x]
|
||||
vectorcall_opcall(2, 0); // [complex(x)]
|
||||
@ -533,7 +549,8 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
if(byte.arg) py_newbool(TOP(), !res);
|
||||
DISPATCH();
|
||||
}
|
||||
TypeError();
|
||||
// TODO: fallback to __iter__?
|
||||
TypeError("argument of type '%t' is not iterable", SECOND()->type);
|
||||
goto __ERROR;
|
||||
}
|
||||
/*****************************************/
|
||||
@ -614,6 +631,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
case OP_CALL: {
|
||||
pk_ManagedHeap__collect_if_needed(&self->heap);
|
||||
vectorcall_opcall(byte.arg & 0xFF, byte.arg >> 8);
|
||||
DISPATCH();
|
||||
}
|
||||
case OP_CALL_VARGS: {
|
||||
assert(false);
|
||||
@ -648,18 +666,12 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
DISPATCH();
|
||||
}
|
||||
// case OP_UNARY_STAR: TOP() = VAR(StarWrapper(byte.arg, TOP())); DISPATCH();
|
||||
// case OP_UNARY_INVERT: {
|
||||
// PyVar _0;
|
||||
// auto _ti = _tp_info(TOP());
|
||||
// if(_ti->m__invert__)
|
||||
// _0 = _ti->m__invert__(this, TOP());
|
||||
// else
|
||||
// _0 = call_method(TOP(), __invert__);
|
||||
// TOP() = _0;
|
||||
// DISPATCH();
|
||||
// }
|
||||
|
||||
default: PK_UNREACHABLE();
|
||||
case OP_UNARY_INVERT: {
|
||||
if(!py_callmagic(__invert__, 1, TOP())) goto __ERROR;
|
||||
*TOP() = self->last_retval;
|
||||
DISPATCH();
|
||||
}
|
||||
default: c11__unreachedable();
|
||||
}
|
||||
|
||||
assert(false); // should never reach here
|
||||
@ -667,7 +679,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
||||
__ERROR:
|
||||
// 1. Exception can be handled inside the current frame
|
||||
// 2. Exception need to be propagated to the upper frame
|
||||
printf("byte.op: %d, line: %d\n", byte.op, Frame__lineno(frame));
|
||||
printf("error.op: %s, line: %d\n", pk_opname(byte.op), Frame__lineno(frame));
|
||||
assert(false);
|
||||
return RES_ERROR;
|
||||
}
|
||||
@ -714,7 +726,7 @@ static bool stack_binaryop(pk_VM* self, py_Name op, py_Name rop) {
|
||||
}
|
||||
}
|
||||
// eq/ne op never fails due to object.__eq__
|
||||
return BinaryOptError(byte.arg);
|
||||
return py_exception("TypeError", "unsupported operand type(s) for '%n'", op);
|
||||
}
|
||||
|
||||
bool py_binaryop(const py_Ref lhs, const py_Ref rhs, py_Name op, py_Name rop) {
|
||||
|
@ -20,7 +20,7 @@ pk_NameDict* FastLocals__to_namedict(py_TValue* locals, const CodeObject* co) {
|
||||
pk_NameDict* dict = pk_NameDict__new();
|
||||
c11__foreach(c11_smallmap_n2i_KV, &co->varnames_inv, entry) {
|
||||
py_TValue value = locals[entry->value];
|
||||
if(!py_isnull(&value)){
|
||||
if(!py_isnil(&value)){
|
||||
pk_NameDict__set(dict, entry->key, value);
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#define DEF_NUM_BINARY_OP(name, op, rint, rfloat) \
|
||||
static bool _py_int##name(int argc, py_Ref argv) { \
|
||||
py_checkargc(2); \
|
||||
PY_CHECK_ARGC(2); \
|
||||
if(py_isint(&argv[1])) { \
|
||||
int64_t lhs = py_toint(&argv[0]); \
|
||||
int64_t rhs = py_toint(&argv[1]); \
|
||||
@ -20,7 +20,7 @@
|
||||
return true; \
|
||||
} \
|
||||
static bool _py_float##name(int argc, py_Ref argv) { \
|
||||
py_checkargc(2); \
|
||||
PY_CHECK_ARGC(2); \
|
||||
double lhs = py_tofloat(&argv[0]); \
|
||||
double rhs; \
|
||||
if(py_castfloat(&argv[1], &rhs)) { \
|
||||
@ -44,24 +44,22 @@ DEF_NUM_BINARY_OP(__ge__, >=, py_newbool, py_newbool)
|
||||
|
||||
#undef DEF_NUM_BINARY_OP
|
||||
|
||||
static bool ValueError(const char* fmt, ...) { return false; }
|
||||
|
||||
static bool _py_int__neg__(int argc, py_Ref argv) {
|
||||
py_checkargc(1);
|
||||
PY_CHECK_ARGC(1);
|
||||
int64_t val = py_toint(&argv[0]);
|
||||
py_newint(py_retval(), -val);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_float__neg__(int argc, py_Ref argv) {
|
||||
py_checkargc(1);
|
||||
PY_CHECK_ARGC(1);
|
||||
double val = py_tofloat(&argv[0]);
|
||||
py_newfloat(py_retval(), -val);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_int__truediv__(int argc, py_Ref argv) {
|
||||
py_checkargc(2);
|
||||
PY_CHECK_ARGC(2);
|
||||
int64_t lhs = py_toint(&argv[0]);
|
||||
double rhs;
|
||||
if(py_castfloat(&argv[1], &rhs)) {
|
||||
@ -73,7 +71,7 @@ static bool _py_int__truediv__(int argc, py_Ref argv) {
|
||||
}
|
||||
|
||||
static bool _py_float__truediv__(int argc, py_Ref argv) {
|
||||
py_checkargc(2);
|
||||
PY_CHECK_ARGC(2);
|
||||
double lhs = py_tofloat(&argv[0]);
|
||||
double rhs;
|
||||
if(py_castfloat(&argv[1], &rhs)) {
|
||||
@ -87,7 +85,7 @@ static bool _py_float__truediv__(int argc, py_Ref argv) {
|
||||
#define ZeroDivisionError(msg) false
|
||||
|
||||
static bool _py_number__pow__(int argc, py_Ref argv) {
|
||||
py_checkargc(2);
|
||||
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]);
|
||||
@ -121,7 +119,7 @@ static bool _py_number__pow__(int argc, py_Ref argv) {
|
||||
}
|
||||
|
||||
static bool _py_int__floordiv__(int argc, py_Ref argv) {
|
||||
py_checkargc(2);
|
||||
PY_CHECK_ARGC(2);
|
||||
int64_t lhs = py_toint(&argv[0]);
|
||||
if(py_isint(&argv[1])) {
|
||||
int64_t rhs = py_toint(&argv[1]);
|
||||
@ -134,7 +132,7 @@ static bool _py_int__floordiv__(int argc, py_Ref argv) {
|
||||
}
|
||||
|
||||
static bool _py_int__mod__(int argc, py_Ref argv) {
|
||||
py_checkargc(2);
|
||||
PY_CHECK_ARGC(2);
|
||||
int64_t lhs = py_toint(&argv[0]);
|
||||
if(py_isint(&argv[1])) {
|
||||
int64_t rhs = py_toint(&argv[1]);
|
||||
@ -147,14 +145,14 @@ static bool _py_int__mod__(int argc, py_Ref argv) {
|
||||
}
|
||||
|
||||
static bool _py_int__invert__(int argc, py_Ref argv) {
|
||||
py_checkargc(1);
|
||||
PY_CHECK_ARGC(1);
|
||||
int64_t val = py_toint(&argv[0]);
|
||||
py_newint(py_retval(), ~val);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_int__bit_length(int argc, py_Ref argv) {
|
||||
py_checkargc(1);
|
||||
PY_CHECK_ARGC(1);
|
||||
int64_t x = py_toint(py_arg(0));
|
||||
if(x < 0) x = -x;
|
||||
int bits = 0;
|
||||
@ -168,7 +166,7 @@ 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_checkargc(2); \
|
||||
PY_CHECK_ARGC(2); \
|
||||
int64_t lhs = py_toint(&argv[0]); \
|
||||
if(py_isint(&argv[1])) { \
|
||||
int64_t rhs = py_toint(&argv[1]); \
|
||||
@ -188,7 +186,7 @@ DEF_INT_BITWISE_OP(__rshift__, >>)
|
||||
#undef DEF_INT_BITWISE_OP
|
||||
|
||||
static bool _py_int__repr__(int argc, py_Ref argv) {
|
||||
py_checkargc(1);
|
||||
PY_CHECK_ARGC(1);
|
||||
int64_t val = py_toint(&argv[0]);
|
||||
char buf[32];
|
||||
int size = snprintf(buf, sizeof(buf), "%lld", (long long)val);
|
||||
@ -197,7 +195,7 @@ static bool _py_int__repr__(int argc, py_Ref argv) {
|
||||
}
|
||||
|
||||
static bool _py_float__repr__(int argc, py_Ref argv) {
|
||||
py_checkargc(1);
|
||||
PY_CHECK_ARGC(1);
|
||||
double val = py_tofloat(&argv[0]);
|
||||
char buf[32];
|
||||
int size = snprintf(buf, sizeof(buf), "%f", val);
|
||||
@ -224,7 +222,7 @@ static py_i64 c11_8bytes__hash(union c11_8bytes u) {
|
||||
}
|
||||
|
||||
static bool _py_int__hash__(int argc, py_Ref argv) {
|
||||
py_checkargc(1);
|
||||
PY_CHECK_ARGC(1);
|
||||
int64_t val = py_toint(&argv[0]);
|
||||
union c11_8bytes u = {._i64 = val};
|
||||
py_newint(py_retval(), c11_8bytes__hash(u));
|
||||
@ -232,7 +230,7 @@ static bool _py_int__hash__(int argc, py_Ref argv) {
|
||||
}
|
||||
|
||||
static bool _py_float__hash__(int argc, py_Ref argv) {
|
||||
py_checkargc(1);
|
||||
PY_CHECK_ARGC(1);
|
||||
double val = py_tofloat(&argv[0]);
|
||||
union c11_8bytes u = {._f64 = val};
|
||||
py_newint(py_retval(), c11_8bytes__hash(u));
|
||||
@ -272,11 +270,12 @@ static bool _py_int__new__(int argc, py_Ref argv) {
|
||||
// 1 or 2 args with str
|
||||
int base = 10;
|
||||
if(argc == 1 + 2) {
|
||||
if(!py_checktype(py_arg(2), tp_int)) return false;
|
||||
PY_CHECK_ARG_TYPE(2, tp_int);
|
||||
base = py_toint(py_arg(2));
|
||||
}
|
||||
|
||||
if(!py_checktype(py_arg(1), tp_str)) return false;
|
||||
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||
|
||||
int size;
|
||||
const char* data = py_tostrn(py_arg(1), &size);
|
||||
bool negative = false;
|
||||
@ -335,14 +334,12 @@ static bool _py_float__new__(int argc, py_Ref argv) {
|
||||
|
||||
char* p_end;
|
||||
py_f64 float_out = strtod(data, &p_end);
|
||||
if(p_end != data + size){
|
||||
return ValueError("invalid literal for float(): %q", data);
|
||||
}
|
||||
if(p_end != data + size) { return ValueError("invalid literal for float(): %q", data); }
|
||||
py_newfloat(py_retval(), float_out);
|
||||
return true;
|
||||
}
|
||||
|
||||
void pk_VM__init_builtins(pk_VM* self) {
|
||||
void pk_number__register() {
|
||||
/****** tp_int & tp_float ******/
|
||||
py_bindmagic(tp_int, __add__, _py_int__add__);
|
||||
py_bindmagic(tp_float, __add__, _py_float__add__);
|
||||
|
@ -41,13 +41,14 @@ void pk_TypeInfo__ctor(pk_TypeInfo* self,
|
||||
// create type object with __dict__
|
||||
pk_ManagedHeap* heap = &pk_current_vm->heap;
|
||||
PyObject* typeobj = pk_ManagedHeap__new(heap, tp_type, -1, sizeof(py_Type));
|
||||
*(py_Type*)PyObject__userdata(typeobj) = index;
|
||||
self->self = (py_TValue){
|
||||
.type = typeobj->type,
|
||||
.is_ptr = true,
|
||||
._obj = typeobj,
|
||||
};
|
||||
|
||||
self->module = module ? *module : PY_NULL;
|
||||
self->module = module ? *module : PY_NIL;
|
||||
self->subclass_enabled = subclass_enabled;
|
||||
|
||||
c11_vector__ctor(&self->annotated_fields, sizeof(py_Name));
|
||||
@ -55,26 +56,32 @@ 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;
|
||||
|
||||
pk_NameDict__ctor(&self->modules);
|
||||
c11_vector__ctor(&self->types, sizeof(pk_TypeInfo));
|
||||
|
||||
self->StopIteration = PY_NULL;
|
||||
self->builtins = PY_NULL;
|
||||
self->main = PY_NULL;
|
||||
self->StopIteration = PY_NIL;
|
||||
self->builtins = PY_NIL;
|
||||
self->main = PY_NIL;
|
||||
|
||||
self->_ceval_on_step = NULL;
|
||||
self->_import_file = pk_default_import_file;
|
||||
self->_stdout = pk_default_stdout;
|
||||
self->_stderr = pk_default_stderr;
|
||||
|
||||
self->last_retval = PY_NULL;
|
||||
self->last_retval = PY_NIL;
|
||||
self->has_error = false;
|
||||
|
||||
self->__curr_class = PY_NULL;
|
||||
self->__cached_object_new = PY_NULL;
|
||||
self->__curr_class = PY_NIL;
|
||||
self->__dynamic_func_decl = NULL;
|
||||
|
||||
pk_ManagedHeap__ctor(&self->heap, self);
|
||||
@ -91,6 +98,7 @@ void pk_VM__ctor(pk_VM* self) {
|
||||
|
||||
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));
|
||||
pk_number__register();
|
||||
validate(tp_bool, pk_VM__new_type(self, "bool", tp_object, NULL, false));
|
||||
validate(tp_str, pk_str__register());
|
||||
|
||||
@ -147,7 +155,7 @@ void pk_VM__ctor(pk_VM* self) {
|
||||
tp_stop_iteration,
|
||||
tp_syntax_error};
|
||||
|
||||
for(int i = 0; i < PK_ARRAY_COUNT(public_types); i++) {
|
||||
for(int i = 0; i < c11__count_array(public_types); i++) {
|
||||
py_Type t = public_types[i];
|
||||
pk_TypeInfo* ti = c11__at(pk_TypeInfo, &self->types, t);
|
||||
py_setdict(&self->builtins, ti->name, py_tpobject(t));
|
||||
@ -158,7 +166,9 @@ void pk_VM__ctor(pk_VM* self) {
|
||||
py_setdict(&self->builtins, py_name("NotImplemented"), &tmp);
|
||||
|
||||
/* Do Buildin Bindings*/
|
||||
pk_VM__init_builtins(self);
|
||||
// object.__new__
|
||||
py_bindmagic(tp_object, __new__, _py_object__new__);
|
||||
|
||||
self->main = *py_newmodule("__main__", NULL);
|
||||
}
|
||||
|
||||
@ -199,16 +209,16 @@ py_Type pk_VM__new_type(pk_VM* self,
|
||||
return index;
|
||||
}
|
||||
|
||||
pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t ARGC, uint16_t KWARGC, bool opcall) {
|
||||
py_Ref p1 = self->stack.sp - KWARGC * 2;
|
||||
py_Ref p0 = p1 - ARGC - 2;
|
||||
pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bool opcall) {
|
||||
py_Ref p1 = self->stack.sp - kwargc * 2;
|
||||
py_Ref p0 = p1 - argc - 2;
|
||||
// [callable, <self>, args..., kwargs...]
|
||||
// ^p0 ^p1 ^_sp
|
||||
|
||||
// handle boundmethod, do a patch
|
||||
if(p0->type == tp_bound_method) {
|
||||
assert(false);
|
||||
assert(py_isnull(p0+1)); // self must be NULL
|
||||
assert(py_isnil(p0 + 1)); // self must be NULL
|
||||
// BoundMethod& bm = PK_OBJ_GET(BoundMethod, callable);
|
||||
// callable = bm.func; // get unbound method
|
||||
// callable_t = _tp(callable);
|
||||
@ -218,7 +228,7 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t ARGC, uint16_t KWARGC, bo
|
||||
}
|
||||
|
||||
// PyVar* _base = args.begin();
|
||||
py_Ref argv = py_isnull(p0+1) ? p0+2 : p0+1;
|
||||
py_Ref argv = py_isnil(p0 + 1) ? p0 + 2 : p0 + 1;
|
||||
|
||||
#if 0
|
||||
if(callable_t == tp_function) {
|
||||
@ -253,7 +263,7 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t ARGC, uint16_t KWARGC, bo
|
||||
// [callable, <self>, args..., local_vars...]
|
||||
// ^p0 ^p1 ^_sp
|
||||
s_data.reset(_base + co->nlocals);
|
||||
// initialize local variables to PY_NULL
|
||||
// initialize local variables to PY_NIL
|
||||
std::memset(p1, 0, (char*)s_data._sp - (char*)p1);
|
||||
break;
|
||||
case FuncType_EMPTY:
|
||||
@ -275,7 +285,7 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t ARGC, uint16_t KWARGC, bo
|
||||
return __py_generator(
|
||||
callstack.popx(),
|
||||
ArgsView(__vectorcall_buffer, __vectorcall_buffer + co->nlocals));
|
||||
default: PK_UNREACHABLE()
|
||||
default: c11__unreachedable()
|
||||
};
|
||||
|
||||
// simple or normal
|
||||
@ -301,7 +311,8 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t ARGC, uint16_t KWARGC, bo
|
||||
// if(f.argc != -1) {
|
||||
// if(KWARGC != 0)
|
||||
// TypeError(
|
||||
// "old-style native_func does not accept keyword arguments. If you want to skip this check, specify `argc` to -1");
|
||||
// "old-style native_func does not accept keyword arguments. If you want to
|
||||
// skip this check, specify `argc` to -1");
|
||||
// if(args.size() != f.argc) {
|
||||
// vm->TypeError(_S("expected ", f.argc, " arguments, got ", args.size()));
|
||||
// }
|
||||
@ -309,64 +320,59 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t ARGC, uint16_t KWARGC, bo
|
||||
// ret = f.call(this, args);
|
||||
// }
|
||||
|
||||
if(!p0->_cfunc(ARGC, argv)) return RES_ERROR;
|
||||
// `argc` passed to _cfunc must include self if exists
|
||||
if(!p0->_cfunc(p1 - argv, argv)) return RES_ERROR;
|
||||
self->stack.sp = p0;
|
||||
return RES_RETURN;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if(p0->type == tp_type) {
|
||||
// [type, NULL, args..., kwargs...]
|
||||
PyVar new_f = *find_name_in_mro(PK_OBJ_GET(Type, callable), __new__);
|
||||
PyVar obj;
|
||||
assert(new_f && (!p0[1]));
|
||||
if(PyVar__IS_OP(&new_f, &__cached_object_new)) {
|
||||
// fast path for object.__new__
|
||||
obj = vm->new_object<DummyInstance>(PK_OBJ_GET(Type, callable));
|
||||
} else {
|
||||
PUSH(new_f);
|
||||
PUSH(PY_NULL);
|
||||
PUSH(callable); // cls
|
||||
for(PyVar o: args)
|
||||
PUSH(o);
|
||||
for(PyVar o: kwargs)
|
||||
PUSH(o);
|
||||
// if obj is not an instance of `cls`, the behavior is undefined
|
||||
obj = vectorcall(ARGC + 1, KWARGC);
|
||||
}
|
||||
// [cls, NULL, args..., kwargs...]
|
||||
py_Ref new_f = py_tpfindmagic(py_totype(p0), __new__);
|
||||
assert(new_f && py_isnil(p0 + 1));
|
||||
|
||||
// __init__
|
||||
PyVar self;
|
||||
callable = get_unbound_method(obj, __init__, &self, false);
|
||||
if(callable) {
|
||||
callable_t = _tp(callable);
|
||||
// replace `NULL` with `self`
|
||||
p1[-(ARGC + 2)] = callable;
|
||||
p1[-(ARGC + 1)] = self;
|
||||
// [init_f, self, args..., kwargs...]
|
||||
vectorcall(ARGC, KWARGC);
|
||||
// We just discard the return value of `__init__`
|
||||
// in cpython it raises a TypeError if the return value is not None
|
||||
// prepare a copy of args and kwargs
|
||||
int span = self->stack.sp - argv;
|
||||
*self->stack.sp++ = *new_f; // push __new__
|
||||
*self->stack.sp++ = *p0; // push cls
|
||||
memcpy(self->stack.sp, argv, span * sizeof(py_TValue));
|
||||
self->stack.sp += span;
|
||||
|
||||
// [new_f, cls, args..., kwargs...]
|
||||
pk_FrameResult res = pk_VM__vectorcall(self, argc, kwargc, false);
|
||||
if(res == RES_ERROR) return RES_ERROR;
|
||||
assert(res == RES_RETURN);
|
||||
// by recursively using vectorcall, args and kwargs are consumed
|
||||
// [cls, NULL, args..., kwargs...]
|
||||
|
||||
// try __init__
|
||||
// NOTE: previous we use `get_unbound_method` but here we just use `tpfindmagic`
|
||||
py_Ref init_f = py_tpfindmagic(py_totype(p0), __init__);
|
||||
if(init_f) {
|
||||
// do an inplace patch
|
||||
*p0 = *init_f; // __init__
|
||||
p0[1] = self->last_retval; // self
|
||||
// [__init__, self, args..., kwargs...]
|
||||
pk_FrameResult res = pk_VM__vectorcall(self, argc, kwargc, false);
|
||||
if(res == RES_ERROR) return RES_ERROR;
|
||||
assert(res == RES_RETURN);
|
||||
} else {
|
||||
// manually reset the stack
|
||||
s_data.reset(p0);
|
||||
self->stack.sp = p0;
|
||||
}
|
||||
return obj;
|
||||
return RES_RETURN;
|
||||
}
|
||||
|
||||
// handle `__call__` overload
|
||||
PyVar self;
|
||||
PyVar call_f = get_unbound_method(callable, __call__, &self, false);
|
||||
if(self) {
|
||||
p1[-(ARGC + 2)] = call_f;
|
||||
p1[-(ARGC + 1)] = self;
|
||||
// [call_f, self, args..., kwargs...]
|
||||
return vectorcall(ARGC, KWARGC, op_call);
|
||||
if(py_getunboundmethod(p0, __call__, p0, p0 + 1)) {
|
||||
// [__call__, self, args..., kwargs...]
|
||||
pk_FrameResult res = pk_VM__vectorcall(self, argc, kwargc, false);
|
||||
if(res == RES_ERROR) return RES_ERROR;
|
||||
assert(res == RES_RETURN);
|
||||
}
|
||||
TypeError(_type_name(vm, callable_t).escape() + " object is not callable");
|
||||
#endif
|
||||
|
||||
PK_UNREACHABLE();
|
||||
TypeError("'%t' object is not callable", p0->type);
|
||||
c11__unreachedable();
|
||||
}
|
||||
|
||||
/****************************************/
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include "pocketpy/objects/base.h"
|
||||
|
||||
py_TValue PY_NULL = {.type=0, .is_ptr=false, .extra=0, ._i64=0};
|
||||
py_TValue PY_NIL = {.type=0, .is_ptr=false, .extra=0, ._i64=0};
|
||||
|
||||
|
@ -89,7 +89,7 @@ static int pkpy_Dict__probe0(const pkpy_Dict* self, py_TValue key, int hash) {
|
||||
struct pkpy_DictEntry* entry = &c11__getitem(struct pkpy_DictEntry, &self->_entries, idx);
|
||||
if(pkpy_Var__is_null(&entry->key)) return h;
|
||||
}
|
||||
PK_UNREACHABLE();
|
||||
c11__unreachedable();
|
||||
}
|
||||
|
||||
static int pkpy_Dict__probe1(const pkpy_Dict* self, py_TValue key, int hash) {
|
||||
@ -103,7 +103,7 @@ static int pkpy_Dict__probe1(const pkpy_Dict* self, py_TValue key, int hash) {
|
||||
if(pkpy_Var__is_null(&entry->key)) continue;
|
||||
if(py_eq(&entry->key, &key)) return h;
|
||||
}
|
||||
PK_UNREACHABLE();
|
||||
c11__unreachedable();
|
||||
}
|
||||
|
||||
static void pkpy_Dict__extendht(pkpy_Dict* self) {
|
||||
|
@ -1,6 +1,9 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
void py_printexc(){
|
||||
pk_VM* vm = pk_current_vm;
|
||||
if(vm->has_error){
|
||||
@ -14,3 +17,22 @@ void py_printexc(){
|
||||
void py_formatexc(char *out){
|
||||
|
||||
}
|
||||
|
||||
bool py_exception(const char* name, const char* fmt, ...){
|
||||
pk_VM* vm = pk_current_vm;
|
||||
assert(!vm->has_error); // an error is already set
|
||||
vm->has_error = true;
|
||||
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
pk_vsprintf(&buf, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
c11_string* res = c11_sbuf__submit(&buf);
|
||||
// vm->last_retval = py_newexception(name, res->data);
|
||||
vm->_stderr("%s: %s\n", name, res->data);
|
||||
c11_string__delete(res);
|
||||
return false;
|
||||
}
|
@ -6,13 +6,6 @@
|
||||
|
||||
typedef c11_vector List;
|
||||
|
||||
py_Type pk_list__register() {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
py_Type type = pk_VM__new_type(vm, "list", tp_object, NULL, false);
|
||||
pk_TypeInfo* ti = c11__at(pk_TypeInfo, &vm->types, type);
|
||||
ti->dtor = (void (*)(void*))c11_vector__dtor;
|
||||
return type;
|
||||
}
|
||||
|
||||
void py_newlist(py_Ref out) {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
@ -67,9 +60,19 @@ void py_list__insert(py_Ref self, int i, const py_Ref val) {
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
bool _py_list__len__(int argc, py_Ref argv){
|
||||
py_checkargc(1);
|
||||
static bool _py_list__len__(int argc, py_Ref argv){
|
||||
PY_CHECK_ARGC(1);
|
||||
py_i64 res = py_list__len(py_arg(0));
|
||||
py_newint(py_retval(), res);
|
||||
return true;
|
||||
}
|
||||
|
||||
py_Type pk_list__register() {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
py_Type type = pk_VM__new_type(vm, "list", tp_object, NULL, false);
|
||||
pk_TypeInfo* ti = c11__at(pk_TypeInfo, &vm->types, type);
|
||||
ti->dtor = (void (*)(void*))c11_vector__dtor;
|
||||
|
||||
py_bindmagic(type, __len__, _py_list__len__);
|
||||
return type;
|
||||
}
|
@ -21,11 +21,11 @@ int py_bool(const py_Ref val) { return 1; }
|
||||
|
||||
bool py_hash(const py_Ref val, int64_t* out) { return 0; }
|
||||
|
||||
bool py_getattr(const py_Ref self, py_Name name, py_Ref out) { return true; }
|
||||
int py_getattr(const py_Ref self, py_Name name, py_Ref out) { return -1; }
|
||||
|
||||
bool py_setattr(py_Ref self, py_Name name, const py_Ref val) { return -1; }
|
||||
bool py_setattr(py_Ref self, py_Name name, const py_Ref val) { return false; }
|
||||
|
||||
bool py_delattr(py_Ref self, py_Name name) { return -1; }
|
||||
bool py_delattr(py_Ref self, py_Name name) { return false; }
|
||||
|
||||
bool py_getitem(const py_Ref self, const py_Ref key, py_Ref out) { return -1; }
|
||||
|
||||
|
@ -13,7 +13,7 @@ py_Ref py_getdict(const py_Ref self, py_Name name){
|
||||
if(self->type == tp_type && py_ismagicname(name)){
|
||||
py_Type* ud = py_touserdata(self);
|
||||
py_Ref slot = py_tpmagic(*ud, name);
|
||||
return py_isnull(slot) ? NULL : slot;
|
||||
return py_isnil(slot) ? NULL : slot;
|
||||
}
|
||||
return pk_NameDict__try_get(PyObject__dict(self->_obj), name);
|
||||
}
|
||||
@ -66,6 +66,6 @@ void py_push(const py_Ref src){
|
||||
|
||||
py_Ref py_pushtmp(){
|
||||
pk_VM* vm = pk_current_vm;
|
||||
py_newnull(vm->stack.sp++);
|
||||
py_newnil(vm->stack.sp++);
|
||||
return py_gettop();
|
||||
}
|
@ -39,7 +39,7 @@ void py_newellipsis(py_Ref out) {
|
||||
out->is_ptr = false;
|
||||
}
|
||||
|
||||
void py_newnull(py_Ref out) { out->type = 0; }
|
||||
void py_newnil(py_Ref out) { out->type = 0; }
|
||||
|
||||
|
||||
void py_newfunction(py_Ref out, py_CFunction f, const char* sig) {
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#include "pocketpy/objects/sourcedata.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
@ -25,13 +26,16 @@ void py_finalize() {
|
||||
pk_MemoryPools__finalize();
|
||||
}
|
||||
|
||||
static void disassemble(CodeObject* co) {
|
||||
const char* pk_opname(Opcode op) {
|
||||
const static char* OP_NAMES[] = {
|
||||
#define OPCODE(name) #name,
|
||||
#include "pocketpy/xmacros/opcodes.h"
|
||||
#undef OPCODE
|
||||
};
|
||||
return OP_NAMES[op];
|
||||
}
|
||||
|
||||
static void disassemble(CodeObject* co) {
|
||||
c11_vector /*T=int*/ jumpTargets;
|
||||
c11_vector__ctor(&jumpTargets, sizeof(int));
|
||||
for(int i = 0; i < co->codes.count; i++) {
|
||||
@ -71,9 +75,9 @@ static void disassemble(CodeObject* co) {
|
||||
snprintf(buf, sizeof(buf), "%-8s%-3s%-3d ", line, pointer, i);
|
||||
c11_sbuf__write_cstr(&ss, buf);
|
||||
|
||||
c11_sbuf__write_cstr(&ss, OP_NAMES[byte.op]);
|
||||
c11_sbuf__write_cstr(&ss, pk_opname(byte.op));
|
||||
c11_sbuf__write_char(&ss, ex.is_virtual ? '*' : ' ');
|
||||
int padding = 24 - strlen(OP_NAMES[byte.op]);
|
||||
int padding = 24 - strlen(pk_opname(byte.op));
|
||||
for(int j = 0; j < padding; j++)
|
||||
c11_sbuf__write_char(&ss, ' ');
|
||||
|
||||
@ -173,7 +177,7 @@ static bool
|
||||
PK_DECREF(src);
|
||||
if(res == RES_ERROR) return false;
|
||||
if(res == RES_RETURN) return true;
|
||||
PK_UNREACHABLE();
|
||||
c11__unreachedable();
|
||||
}
|
||||
|
||||
bool py_exec(const char* source) { return pk_VM__exec(pk_current_vm, source, "<exec>", EXEC_MODE); }
|
||||
@ -191,12 +195,42 @@ bool py_vectorcall(uint16_t argc, uint16_t kwargc) {
|
||||
|
||||
py_Ref py_retval() { return &pk_current_vm->last_retval; }
|
||||
|
||||
bool py_getunboundmethod(const py_Ref self,
|
||||
py_Name name,
|
||||
bool fallback,
|
||||
py_Ref out,
|
||||
py_Ref out_self) {
|
||||
return -1;
|
||||
bool py_getunboundmethod(py_Ref self, py_Name name, py_Ref out, py_Ref out_self) {
|
||||
// NOTE: `out` and `out_self` may overlap with `self`
|
||||
py_Type type;
|
||||
// handle super() proxy
|
||||
if(py_istype(self, tp_super)) {
|
||||
self = py_getslot(self, 0);
|
||||
type = *(py_Type*)py_touserdata(self);
|
||||
} else {
|
||||
type = self->type;
|
||||
}
|
||||
|
||||
py_Ref cls_var = py_tpfindname(type, name);
|
||||
if(cls_var != NULL) {
|
||||
switch(cls_var->type) {
|
||||
case tp_function:
|
||||
case tp_nativefunc: {
|
||||
py_TValue self_bak = *self;
|
||||
// `out` may overlap with `self`. If we assign `out`, `self` may be corrupted.
|
||||
*out = *cls_var;
|
||||
*out_self = self_bak;
|
||||
break;
|
||||
}
|
||||
case tp_staticmethod:
|
||||
*out = *py_getslot(cls_var, 0);
|
||||
py_newnil(out_self);
|
||||
break;
|
||||
case tp_classmethod:
|
||||
*out = *py_getslot(cls_var, 0);
|
||||
*out_self = c11__getitem(pk_TypeInfo, &pk_current_vm->types, type).self;
|
||||
break;
|
||||
default: c11__unreachedable();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// TODO: __getattr__ fallback
|
||||
return false;
|
||||
}
|
||||
|
||||
pk_TypeInfo* pk_tpinfo(const py_Ref self) {
|
||||
@ -209,7 +243,17 @@ py_Ref py_tpfindmagic(py_Type t, py_Name name) {
|
||||
pk_TypeInfo* types = (pk_TypeInfo*)pk_current_vm->types.data;
|
||||
do {
|
||||
py_Ref f = &types[t].magic[name];
|
||||
if(!py_isnull(f)) return f;
|
||||
if(!py_isnil(f)) return f;
|
||||
t = types[t].base;
|
||||
} while(t);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
py_Ref py_tpfindname(py_Type t, py_Name name) {
|
||||
pk_TypeInfo* types = (pk_TypeInfo*)pk_current_vm->types.data;
|
||||
do {
|
||||
py_Ref res = py_getdict(&types[t].self, name);
|
||||
if(res) return res;
|
||||
t = types[t].base;
|
||||
} while(t);
|
||||
return NULL;
|
||||
@ -227,6 +271,7 @@ py_Ref py_tpobject(py_Type type) {
|
||||
}
|
||||
|
||||
const char* py_tpname(py_Type type) {
|
||||
if(!type) return "nil";
|
||||
pk_VM* vm = pk_current_vm;
|
||||
py_Name name = c11__at(pk_TypeInfo, &vm->types, type)->name;
|
||||
return py_name2str(name);
|
||||
@ -236,7 +281,9 @@ 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 TypeError(name);
|
||||
if(!tmp){
|
||||
return AttributeError(argv, name);
|
||||
}
|
||||
if(tmp->type == tp_nativefunc) return tmp->_cfunc(argc, argv);
|
||||
return py_call(tmp, argc, argv);
|
||||
}
|
||||
|
@ -59,6 +59,8 @@ int main(int argc, char** argv) {
|
||||
py_finalize();
|
||||
free(source);
|
||||
|
||||
return 0;
|
||||
|
||||
__HELP:
|
||||
printf("Usage: pocketpy [filename]\n");
|
||||
return 0;
|
||||
|
103
tests/00_tmp.py
Normal file
103
tests/00_tmp.py
Normal file
@ -0,0 +1,103 @@
|
||||
# test int literals
|
||||
assert 0xffff == 65535
|
||||
assert 0xAAFFFF == 11206655
|
||||
assert 0x7fffffff == 2147483647
|
||||
assert -0xffff == -65535
|
||||
assert -0xAAFFFF == -11206655
|
||||
assert -0x7fffffff == -2147483647
|
||||
# test 64-bit
|
||||
assert 2**60-1 + 546 - 0xfffffffffffff == 1148417904979477026
|
||||
|
||||
# test oct literals
|
||||
assert 0o1234 == 668
|
||||
assert 0o17777777777 == 2147483647
|
||||
assert -0o1234 == -668
|
||||
assert -0o17777777777 == -2147483647
|
||||
|
||||
# test binary literals
|
||||
assert 0b10010 == 18
|
||||
assert -0b10010 == -18
|
||||
assert 0b11111111111111111111111111111111 == 4294967295
|
||||
assert -0b11111 == -31
|
||||
|
||||
# test == != >= <= < >
|
||||
assert -1 == -1
|
||||
assert -1 != 1
|
||||
assert -1 >= -1
|
||||
assert -1 <= -1
|
||||
assert -1 < 1
|
||||
assert -1 > -2
|
||||
|
||||
# test + - * % ** //
|
||||
assert -1 + 1 == 0
|
||||
assert -1 - 1 == -2
|
||||
assert 4 * -1 == -4
|
||||
assert 5 % 2 == 1
|
||||
assert 2 ** 3 == 8
|
||||
assert 4 // 2 == 2
|
||||
assert 5 // 2 == 2
|
||||
|
||||
# test += -= *= //=
|
||||
x = 3
|
||||
x += 1
|
||||
assert x == 4
|
||||
x -= 1
|
||||
assert x == 3
|
||||
x *= 2
|
||||
assert x == 6
|
||||
x //= 2
|
||||
assert x == 3
|
||||
|
||||
# test bit_length
|
||||
assert (1).bit_length() == 1
|
||||
assert (2).bit_length() == 2
|
||||
assert (3).bit_length() == 2
|
||||
|
||||
assert (-1).bit_length() == 1
|
||||
assert (-2).bit_length() == 2
|
||||
assert (-3).bit_length() == 2
|
||||
|
||||
assert (123123123123123).bit_length() == 47
|
||||
assert (-3123123123).bit_length() == 32
|
||||
|
||||
# test int()
|
||||
assert int() == 0
|
||||
assert int(True) == 1
|
||||
assert int(False) == 0
|
||||
|
||||
assert int(1) == 1
|
||||
assert int(1.0) == 1
|
||||
assert int(1.1) == 1
|
||||
assert int(1.9) == 1
|
||||
assert int(-1.9) == -1
|
||||
assert int(1.5) == 1
|
||||
assert int(-1.5) == -1
|
||||
assert int("123") == 123
|
||||
|
||||
assert int("0x123", 16) == 291
|
||||
assert int("0o123", 8) == 83
|
||||
assert int("-0x123", 16) == -291
|
||||
assert int("-0o123", 8) == -83
|
||||
assert int("-123") == -123
|
||||
assert int("+123") == 123
|
||||
|
||||
# test >> << & | ^
|
||||
assert 12 >> 1 == 6
|
||||
assert 12 << 1 == 24
|
||||
assert 12 & 1 == 0
|
||||
assert 12 | 1 == 13
|
||||
assert 12 ^ 1 == 13
|
||||
|
||||
# test high precision int pow
|
||||
assert 7**21 == 558545864083284007
|
||||
assert 2**60 == 1152921504606846976
|
||||
assert -2**60 == -1152921504606846976
|
||||
assert 4**13 == 67108864
|
||||
assert (-4)**13 == -67108864
|
||||
|
||||
assert ~3 == -4
|
||||
assert ~-3 == 2
|
||||
assert ~0 == -1
|
||||
|
||||
# tmp code
|
||||
assert [1, 2].__len__() == 2
|
@ -48,10 +48,6 @@ assert x == 6
|
||||
x //= 2
|
||||
assert x == 3
|
||||
|
||||
# test __str__, __repr__
|
||||
assert str(1) == '1'
|
||||
assert repr(1) == '1'
|
||||
|
||||
# test bit_length
|
||||
assert (1).bit_length() == 1
|
||||
assert (2).bit_length() == 2
|
||||
@ -103,6 +99,10 @@ assert ~3 == -4
|
||||
assert ~-3 == 2
|
||||
assert ~0 == -1
|
||||
|
||||
# test __str__, __repr__
|
||||
assert str(1) == '1'
|
||||
assert repr(1) == '1'
|
||||
|
||||
try:
|
||||
1 // 0
|
||||
exit(1)
|
||||
|
Loading…
x
Reference in New Issue
Block a user