Compare commits

...

7 Commits

Author SHA1 Message Date
blueloveTH
34916d7578 Update ceval.c 2024-07-05 00:21:56 +08:00
blueloveTH
c2944b7fd8 some fix 2024-07-05 00:17:53 +08:00
blueloveTH
4569547161 Update compiler.c 2024-07-04 23:51:05 +08:00
blueloveTH
68bc6ee269 fix leaks 2024-07-04 23:47:32 +08:00
blueloveTH
3da176fbfb some rename 2024-07-04 23:20:52 +08:00
blueloveTH
3a8613b7ff improve errors 2024-07-04 22:44:37 +08:00
blueloveTH
facd1c0ce6 some fix 2024-07-04 19:55:24 +08:00
24 changed files with 495 additions and 276 deletions

View File

@ -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,12 +52,13 @@ 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); \
} \
} while(0)
} while(0)
#ifdef __cplusplus
}

View File

@ -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++)

View File

@ -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();

View File

@ -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
}

View File

@ -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.
*/

View File

@ -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);

View File

@ -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;

View File

@ -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__; }

View File

@ -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;

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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]);
@ -100,7 +98,7 @@ static bool _py_number__pow__(int argc, py_Ref argv) {
} else {
// rhs >= 0
int64_t ret = 1;
while(true){
while(true) {
if(rhs & 1) ret *= lhs;
rhs >>= 1;
if(!rhs) break;
@ -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;
@ -324,25 +323,23 @@ static bool _py_float__new__(int argc, py_Ref argv) {
int size;
const char* data = py_tostrn(py_arg(1), &size);
if(c11__streq(data, "inf")){
if(c11__streq(data, "inf")) {
py_newfloat(py_retval(), INFINITY);
return true;
}
if(c11__streq(data, "-inf")){
if(c11__streq(data, "-inf")) {
py_newfloat(py_retval(), -INFINITY);
return true;
}
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__);

View File

@ -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();
}
/****************************************/

View File

@ -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};

View File

@ -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) {

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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; }

View File

@ -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();
}

View File

@ -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) {

View File

@ -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);
}

View File

@ -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
View 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

View File

@ -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)