mirror of
				https://github.com/pocketpy/pocketpy
				synced 2025-11-03 18:20:17 +00:00 
			
		
		
		
	Compare commits
	
		
			10 Commits
		
	
	
		
			8e1e29ddd6
			...
			0b649f3bef
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					0b649f3bef | ||
| 
						 | 
					a87641c04d | ||
| 
						 | 
					9c173fdada | ||
| 
						 | 
					348bb2b7a5 | ||
| 
						 | 
					39947e8f15 | ||
| 
						 | 
					56763e05f9 | ||
| 
						 | 
					cd9a9f7119 | ||
| 
						 | 
					ea9dabdf99 | ||
| 
						 | 
					b1a8c6db8e | ||
| 
						 | 
					3c87bf8630 | 
							
								
								
									
										
											BIN
										
									
								
								backup/vfs.zip
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								backup/vfs.zip
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							@ -5,6 +5,8 @@
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
const char* load_kPythonLib(const char* name);
 | 
			
		||||
 | 
			
		||||
extern const char kPythonLibs__enum[];
 | 
			
		||||
extern const char kPythonLibs__long[];
 | 
			
		||||
extern const char kPythonLibs__set[];
 | 
			
		||||
 | 
			
		||||
@ -10,7 +10,7 @@
 | 
			
		||||
 | 
			
		||||
// Whether to compile os-related modules or not
 | 
			
		||||
#ifndef PK_ENABLE_OS                // can be overridden by cmake
 | 
			
		||||
#define PK_ENABLE_OS                0
 | 
			
		||||
#define PK_ENABLE_OS                1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Enable `line_profiler` module and `breakpoint()` function
 | 
			
		||||
 | 
			
		||||
@ -11,8 +11,8 @@ extern "C" {
 | 
			
		||||
#define kPoolObjectArenaSize    (256*1024)
 | 
			
		||||
#define kPoolObjectMaxBlocks    (kPoolObjectArenaSize / kPoolObjectBlockSize)
 | 
			
		||||
 | 
			
		||||
void pk_MemoryPools__initialize();
 | 
			
		||||
void pk_MemoryPools__finalize();
 | 
			
		||||
void MemoryPools__initialize();
 | 
			
		||||
void MemoryPools__finalize();
 | 
			
		||||
 | 
			
		||||
void* PoolExpr_alloc();
 | 
			
		||||
void PoolExpr_dealloc(void*);
 | 
			
		||||
 | 
			
		||||
@ -49,6 +49,8 @@ int c11_sv__index(c11_sv self, char c);
 | 
			
		||||
int c11_sv__rindex(c11_sv self, char c);
 | 
			
		||||
int c11_sv__index2(c11_sv self, c11_sv sub, int start);
 | 
			
		||||
int c11_sv__count(c11_sv self, c11_sv sub);
 | 
			
		||||
bool c11_sv__startswith(c11_sv self, c11_sv prefix);
 | 
			
		||||
bool c11_sv__endswith(c11_sv self, c11_sv suffix);
 | 
			
		||||
 | 
			
		||||
c11_string* c11_sv__replace(c11_sv self, char old, char new_);
 | 
			
		||||
c11_string* c11_sv__replace2(c11_sv self, c11_sv old, c11_sv new_);
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
Error* pk_compile(pk_SourceData_ src, CodeObject* out);
 | 
			
		||||
Error* pk_compile(SourceData_ src, CodeObject* out);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -10,7 +10,7 @@
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
extern const char* pk_TokenSymbols[];
 | 
			
		||||
extern const char* TokenSymbols[];
 | 
			
		||||
 | 
			
		||||
typedef enum TokenIndex{
 | 
			
		||||
    TK_EOF, TK_EOL, TK_SOF,
 | 
			
		||||
@ -88,11 +88,11 @@ enum Precedence {
 | 
			
		||||
    PREC_HIGHEST,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef c11_array pk_TokenArray;
 | 
			
		||||
typedef c11_array TokenArray;
 | 
			
		||||
 | 
			
		||||
Error* pk_Lexer__process(pk_SourceData_ src, pk_TokenArray* out_tokens);
 | 
			
		||||
Error* pk_Lexer__process_and_dump(pk_SourceData_ src, c11_string** out_string);
 | 
			
		||||
void pk_TokenArray__dtor(pk_TokenArray* self);
 | 
			
		||||
Error* Lexer__process(SourceData_ src, TokenArray* out_tokens);
 | 
			
		||||
Error* Lexer__process_and_dump(SourceData_ src, c11_string** out_string);
 | 
			
		||||
void TokenArray__dtor(TokenArray* self);
 | 
			
		||||
 | 
			
		||||
#define Token__sv(self) (c11_sv){(self)->start, (self)->length}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,7 @@ extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
py_TValue* FastLocals__try_get_by_name(py_TValue* locals, const CodeObject* co, py_Name name);
 | 
			
		||||
pk_NameDict* FastLocals__to_namedict(py_TValue* locals, const CodeObject* co);
 | 
			
		||||
NameDict* FastLocals__to_namedict(py_TValue* locals, const CodeObject* co);
 | 
			
		||||
 | 
			
		||||
typedef struct ValueStack {
 | 
			
		||||
    // We allocate extra PK_VM_STACK_SIZE/128 places to keep `_sp` valid when `is_overflow() ==
 | 
			
		||||
 | 
			
		||||
@ -5,29 +5,29 @@
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct pk_ManagedHeap{
 | 
			
		||||
typedef struct ManagedHeap{
 | 
			
		||||
    c11_vector no_gc;
 | 
			
		||||
    c11_vector gen;
 | 
			
		||||
 | 
			
		||||
    int gc_threshold;
 | 
			
		||||
    int gc_counter;
 | 
			
		||||
    pk_VM* vm;
 | 
			
		||||
    VM* vm;
 | 
			
		||||
 | 
			
		||||
    void (*gc_on_delete)(pk_VM*, PyObject*);
 | 
			
		||||
} pk_ManagedHeap;
 | 
			
		||||
    void (*gc_on_delete)(VM*, PyObject*);
 | 
			
		||||
} ManagedHeap;
 | 
			
		||||
 | 
			
		||||
void pk_ManagedHeap__ctor(pk_ManagedHeap* self, pk_VM* vm);
 | 
			
		||||
void pk_ManagedHeap__dtor(pk_ManagedHeap* self);
 | 
			
		||||
void ManagedHeap__ctor(ManagedHeap* self, VM* vm);
 | 
			
		||||
void ManagedHeap__dtor(ManagedHeap* self);
 | 
			
		||||
 | 
			
		||||
void pk_ManagedHeap__collect_if_needed(pk_ManagedHeap* self);
 | 
			
		||||
int pk_ManagedHeap__collect(pk_ManagedHeap* self);
 | 
			
		||||
int pk_ManagedHeap__sweep(pk_ManagedHeap* self);
 | 
			
		||||
void ManagedHeap__collect_if_needed(ManagedHeap* self);
 | 
			
		||||
int ManagedHeap__collect(ManagedHeap* self);
 | 
			
		||||
int ManagedHeap__sweep(ManagedHeap* self);
 | 
			
		||||
 | 
			
		||||
PyObject* pk_ManagedHeap__new(pk_ManagedHeap* self, py_Type type, int slots, int udsize);
 | 
			
		||||
PyObject* pk_ManagedHeap__gcnew(pk_ManagedHeap* self, py_Type type, int slots, int udsize);
 | 
			
		||||
PyObject* ManagedHeap__new(ManagedHeap* self, py_Type type, int slots, int udsize);
 | 
			
		||||
PyObject* ManagedHeap__gcnew(ManagedHeap* self, py_Type type, int slots, int udsize);
 | 
			
		||||
 | 
			
		||||
// external implementation
 | 
			
		||||
void pk_ManagedHeap__mark(pk_ManagedHeap* self);
 | 
			
		||||
void ManagedHeap__mark(ManagedHeap* self);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								include/pocketpy/interpreter/modules.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								include/pocketpy/interpreter/modules.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void pk__add_module_pkpy();
 | 
			
		||||
void pk__add_module_os();
 | 
			
		||||
void pk__add_module_math();
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
@ -1,44 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "pocketpy/common/vector.h"
 | 
			
		||||
#include "pocketpy/common/str.h"
 | 
			
		||||
#include "pocketpy/pocketpy.h"
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct VfsEntry {
 | 
			
		||||
    bool is_file;
 | 
			
		||||
 | 
			
		||||
    union {
 | 
			
		||||
        struct {
 | 
			
		||||
            int size;
 | 
			
		||||
            unsigned char* data;
 | 
			
		||||
        } _file;
 | 
			
		||||
 | 
			
		||||
        c11_vector _dir;
 | 
			
		||||
    };
 | 
			
		||||
} VfsEntry;
 | 
			
		||||
 | 
			
		||||
#define SMALLMAP_T__HEADER
 | 
			
		||||
#define K c11_sv
 | 
			
		||||
#define V VfsEntry
 | 
			
		||||
#define NAME VfsDir
 | 
			
		||||
#define less(a, b) (c11_sv__cmp((a), (b)) < 0)
 | 
			
		||||
#define equal(a, b) (c11_sv__cmp((a), (b)) == 0)
 | 
			
		||||
#include "pocketpy/xmacros/smallmap.h"
 | 
			
		||||
#undef SMALLMAP_T__HEADER
 | 
			
		||||
 | 
			
		||||
typedef struct Vfs {
 | 
			
		||||
    VfsEntry root;
 | 
			
		||||
} Vfs;
 | 
			
		||||
 | 
			
		||||
void Vfs__ctor(Vfs* self);
 | 
			
		||||
void Vfs__dtor(Vfs* self);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
@ -4,13 +4,13 @@
 | 
			
		||||
#include "pocketpy/pocketpy.h"
 | 
			
		||||
#include "pocketpy/interpreter/gc.h"
 | 
			
		||||
#include "pocketpy/interpreter/frame.h"
 | 
			
		||||
#include "pocketpy/interpreter/vfs.h"
 | 
			
		||||
#include "pocketpy/interpreter/modules.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct pk_TypeInfo {
 | 
			
		||||
typedef struct py_TypeInfo {
 | 
			
		||||
    py_Name name;
 | 
			
		||||
    py_Type base;
 | 
			
		||||
 | 
			
		||||
@ -24,23 +24,23 @@ typedef struct pk_TypeInfo {
 | 
			
		||||
 | 
			
		||||
    c11_vector /*T=py_Name*/ annotated_fields;
 | 
			
		||||
 | 
			
		||||
    void (*on_end_subclass)(struct pk_TypeInfo*);  // backdoor for enum module
 | 
			
		||||
    void (*on_end_subclass)(struct py_TypeInfo*);  // backdoor for enum module
 | 
			
		||||
 | 
			
		||||
    /* Magic Slots */
 | 
			
		||||
    py_TValue magic[64];
 | 
			
		||||
} pk_TypeInfo;
 | 
			
		||||
} py_TypeInfo;
 | 
			
		||||
 | 
			
		||||
typedef struct pk_VM {
 | 
			
		||||
typedef struct VM {
 | 
			
		||||
    Frame* top_frame;
 | 
			
		||||
 | 
			
		||||
    pk_NameDict modules;
 | 
			
		||||
    c11_vector /*T=pk_TypeInfo*/ types;
 | 
			
		||||
    NameDict modules;
 | 
			
		||||
    c11_vector /*T=py_TypeInfo*/ types;
 | 
			
		||||
 | 
			
		||||
    py_TValue builtins;  // builtins module
 | 
			
		||||
    py_TValue main;      // __main__ module
 | 
			
		||||
 | 
			
		||||
    void (*ceval_on_step)(Frame*, Bytecode);
 | 
			
		||||
    unsigned char* (*import_file)(const char*, int*);
 | 
			
		||||
    char* (*import_file)(const char*);
 | 
			
		||||
    void (*print)(const char*);
 | 
			
		||||
 | 
			
		||||
    py_TValue last_retval;
 | 
			
		||||
@ -49,20 +49,19 @@ typedef struct pk_VM {
 | 
			
		||||
 | 
			
		||||
    py_TValue reg[8];  // users' registers
 | 
			
		||||
 | 
			
		||||
    Vfs __vfs;
 | 
			
		||||
    py_TValue* __curr_class;
 | 
			
		||||
    FuncDecl_ __dynamic_func_decl;
 | 
			
		||||
    py_TValue __vectorcall_buffer[PK_MAX_CO_VARNAMES];
 | 
			
		||||
 | 
			
		||||
    pk_ManagedHeap heap;
 | 
			
		||||
    ManagedHeap heap;
 | 
			
		||||
    ValueStack stack;  // put `stack` at the end for better cache locality
 | 
			
		||||
} pk_VM;
 | 
			
		||||
} VM;
 | 
			
		||||
 | 
			
		||||
void pk_VM__ctor(pk_VM* self);
 | 
			
		||||
void pk_VM__dtor(pk_VM* self);
 | 
			
		||||
void VM__ctor(VM* self);
 | 
			
		||||
void VM__dtor(VM* self);
 | 
			
		||||
 | 
			
		||||
void pk_VM__push_frame(pk_VM* self, Frame* frame);
 | 
			
		||||
void pk_VM__pop_frame(pk_VM* self);
 | 
			
		||||
void VM__push_frame(VM* self, Frame* frame);
 | 
			
		||||
void VM__pop_frame(VM* self);
 | 
			
		||||
 | 
			
		||||
bool pk__parse_int_slice(py_Ref slice, int length, int* start, int* stop, int* step);
 | 
			
		||||
bool pk__normalize_index(int* index, int length);
 | 
			
		||||
@ -70,14 +69,14 @@ bool pk__normalize_index(int* index, int length);
 | 
			
		||||
void pk_list__mark(void* ud, void (*marker)(py_TValue*));
 | 
			
		||||
void pk_dict__mark(void* ud, void (*marker)(py_TValue*));
 | 
			
		||||
 | 
			
		||||
typedef enum pk_FrameResult {
 | 
			
		||||
typedef enum FrameResult {
 | 
			
		||||
    RES_RETURN,
 | 
			
		||||
    RES_CALL,
 | 
			
		||||
    RES_YIELD,
 | 
			
		||||
    RES_ERROR,
 | 
			
		||||
} pk_FrameResult;
 | 
			
		||||
} FrameResult;
 | 
			
		||||
 | 
			
		||||
pk_FrameResult pk_VM__run_top_frame(pk_VM* self);
 | 
			
		||||
FrameResult VM__run_top_frame(VM* self);
 | 
			
		||||
 | 
			
		||||
py_Type pk_newtype(const char* name,
 | 
			
		||||
                   py_Type base,
 | 
			
		||||
@ -86,7 +85,7 @@ py_Type pk_newtype(const char* name,
 | 
			
		||||
                   bool is_python,
 | 
			
		||||
                   bool is_sealed);
 | 
			
		||||
 | 
			
		||||
pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bool opcall);
 | 
			
		||||
FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall);
 | 
			
		||||
 | 
			
		||||
const char* pk_opname(Opcode op);
 | 
			
		||||
 | 
			
		||||
@ -101,9 +100,9 @@ bool pk_callmagic(py_Name name, int argc, py_Ref argv);
 | 
			
		||||
/// Assumes [a, b] are on the stack, performs a binary op.
 | 
			
		||||
/// The result is stored in `self->last_retval`.
 | 
			
		||||
/// The stack remains unchanged.
 | 
			
		||||
bool pk_stack_binaryop(pk_VM* self, py_Name op, py_Name rop);
 | 
			
		||||
bool pk_stack_binaryop(VM* self, py_Name op, py_Name rop);
 | 
			
		||||
 | 
			
		||||
void pk_print_stack(pk_VM* self, Frame* frame, Bytecode byte);
 | 
			
		||||
void pk_print_stack(VM* self, Frame* frame, Bytecode byte);
 | 
			
		||||
 | 
			
		||||
// type registration
 | 
			
		||||
void pk_object__register();
 | 
			
		||||
@ -123,11 +122,13 @@ py_Type pk_range__register();
 | 
			
		||||
py_Type pk_range_iterator__register();
 | 
			
		||||
py_Type pk_BaseException__register();
 | 
			
		||||
py_Type pk_Exception__register();
 | 
			
		||||
py_Type pk_super__register();
 | 
			
		||||
py_Type pk_property__register();
 | 
			
		||||
py_Type pk_staticmethod__register();
 | 
			
		||||
py_Type pk_classmethod__register();
 | 
			
		||||
 | 
			
		||||
py_TValue pk_builtins__register();
 | 
			
		||||
 | 
			
		||||
void pk__add_module_pkpy();
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
@ -14,8 +14,8 @@ extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct PyObject PyObject;
 | 
			
		||||
typedef struct pk_VM pk_VM;
 | 
			
		||||
extern pk_VM* pk_current_vm;
 | 
			
		||||
typedef struct VM VM;
 | 
			
		||||
extern VM* pk_current_vm;
 | 
			
		||||
 | 
			
		||||
typedef struct py_TValue {
 | 
			
		||||
    py_Type type;
 | 
			
		||||
 | 
			
		||||
@ -68,7 +68,7 @@ typedef struct BytecodeEx {
 | 
			
		||||
} BytecodeEx;
 | 
			
		||||
 | 
			
		||||
typedef struct CodeObject {
 | 
			
		||||
    pk_SourceData_ src;
 | 
			
		||||
    SourceData_ src;
 | 
			
		||||
    c11_string* name;
 | 
			
		||||
 | 
			
		||||
    c11_vector /*T=Bytecode*/ codes;
 | 
			
		||||
@ -88,7 +88,7 @@ typedef struct CodeObject {
 | 
			
		||||
    int end_line;
 | 
			
		||||
} CodeObject;
 | 
			
		||||
 | 
			
		||||
void CodeObject__ctor(CodeObject* self, pk_SourceData_ src, c11_sv name);
 | 
			
		||||
void CodeObject__ctor(CodeObject* self, SourceData_ src, c11_sv name);
 | 
			
		||||
void CodeObject__dtor(CodeObject* self);
 | 
			
		||||
int CodeObject__add_varname(CodeObject* self, py_Name name);
 | 
			
		||||
void CodeObject__gc_mark(const CodeObject* self);
 | 
			
		||||
@ -118,7 +118,7 @@ typedef struct FuncDecl {
 | 
			
		||||
 | 
			
		||||
typedef FuncDecl* FuncDecl_;
 | 
			
		||||
 | 
			
		||||
FuncDecl_ FuncDecl__rcnew(pk_SourceData_ src, c11_sv name);
 | 
			
		||||
FuncDecl_ FuncDecl__rcnew(SourceData_ src, c11_sv name);
 | 
			
		||||
bool FuncDecl__is_duplicated_arg(const FuncDecl* self, py_Name name);
 | 
			
		||||
void FuncDecl__add_arg(FuncDecl* self, py_Name name);
 | 
			
		||||
void FuncDecl__add_kwarg(FuncDecl* self, py_Name name, const py_TValue* value);
 | 
			
		||||
@ -139,7 +139,7 @@ typedef struct Function {
 | 
			
		||||
    FuncDecl_ decl;
 | 
			
		||||
    py_TValue module;      // weak ref
 | 
			
		||||
    PyObject* clazz;       // weak ref
 | 
			
		||||
    pk_NameDict* closure;  // strong ref
 | 
			
		||||
    NameDict* closure;  // strong ref
 | 
			
		||||
    py_CFunction cfunc;    // wrapped C function
 | 
			
		||||
} Function;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -12,14 +12,14 @@ extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct{
 | 
			
		||||
    pk_SourceData_ src;
 | 
			
		||||
    SourceData_ src;
 | 
			
		||||
    int lineno;
 | 
			
		||||
    char msg[100];
 | 
			
		||||
} Error;
 | 
			
		||||
 | 
			
		||||
void py_BaseException__set_lineno(py_Ref, int lineno, const CodeObject* code);
 | 
			
		||||
int py_BaseException__get_lineno(py_Ref, const CodeObject* code);
 | 
			
		||||
void py_BaseException__stpush(py_Ref, pk_SourceData_ src, int lineno, const char* func_name);
 | 
			
		||||
void py_BaseException__stpush(py_Ref, SourceData_ src, int lineno, const char* func_name);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,7 @@ extern "C" {
 | 
			
		||||
#define SMALLMAP_T__HEADER
 | 
			
		||||
#define K uint16_t
 | 
			
		||||
#define V py_TValue
 | 
			
		||||
#define NAME pk_NameDict
 | 
			
		||||
#define NAME NameDict
 | 
			
		||||
#include "pocketpy/xmacros/smallmap.h"
 | 
			
		||||
#undef SMALLMAP_T__HEADER
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -22,10 +22,10 @@ typedef struct PyObject {
 | 
			
		||||
// | HEADER | <dict>    | <userdata>
 | 
			
		||||
 | 
			
		||||
py_TValue* PyObject__slots(PyObject* self);
 | 
			
		||||
pk_NameDict* PyObject__dict(PyObject* self);
 | 
			
		||||
NameDict* PyObject__dict(PyObject* self);
 | 
			
		||||
void* PyObject__userdata(PyObject* self);
 | 
			
		||||
 | 
			
		||||
#define PK_OBJ_SLOTS_SIZE(slots) ((slots) >= 0 ? sizeof(py_TValue) * (slots) : sizeof(pk_NameDict))
 | 
			
		||||
#define PK_OBJ_SLOTS_SIZE(slots) ((slots) >= 0 ? sizeof(py_TValue) * (slots) : sizeof(NameDict))
 | 
			
		||||
 | 
			
		||||
PyObject* PyObject__new(py_Type type, int slots, int size);
 | 
			
		||||
void PyObject__delete(PyObject* self);
 | 
			
		||||
 | 
			
		||||
@ -10,7 +10,7 @@
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct pk_SourceData {
 | 
			
		||||
struct SourceData {
 | 
			
		||||
    RefCounted rc;
 | 
			
		||||
    enum py_CompileMode mode;
 | 
			
		||||
    bool is_precompiled;
 | 
			
		||||
@ -23,17 +23,17 @@ struct pk_SourceData {
 | 
			
		||||
    c11_vector /*T=c11_string* */ _precompiled_tokens;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct pk_SourceData* pk_SourceData_;
 | 
			
		||||
typedef struct SourceData* SourceData_;
 | 
			
		||||
 | 
			
		||||
pk_SourceData_ pk_SourceData__rcnew(const char* source,
 | 
			
		||||
SourceData_ SourceData__rcnew(const char* source,
 | 
			
		||||
                                    const char* filename,
 | 
			
		||||
                                    enum py_CompileMode mode,
 | 
			
		||||
                                    bool is_dynamic);
 | 
			
		||||
bool pk_SourceData__get_line(const struct pk_SourceData* self,
 | 
			
		||||
bool SourceData__get_line(const struct SourceData* self,
 | 
			
		||||
                             int lineno,
 | 
			
		||||
                             const char** st,
 | 
			
		||||
                             const char** ed);
 | 
			
		||||
void pk_SourceData__snapshot(const struct pk_SourceData* self,
 | 
			
		||||
void SourceData__snapshot(const struct SourceData* self,
 | 
			
		||||
                             c11_sbuf* ss,
 | 
			
		||||
                             int lineno,
 | 
			
		||||
                             const char* cursor,
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,10 @@
 | 
			
		||||
#include "pocketpy/common/config.h"
 | 
			
		||||
#include "pocketpy/common/export.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/************* Public Types *************/
 | 
			
		||||
typedef struct py_TValue py_TValue;
 | 
			
		||||
typedef uint16_t py_Name;
 | 
			
		||||
@ -94,6 +98,7 @@ void py_newslice(py_Ref);
 | 
			
		||||
void py_newnativefunc(py_Ref out, py_CFunction);
 | 
			
		||||
py_Name
 | 
			
		||||
    py_newfunction(py_Ref out, const char* sig, py_CFunction f, const char* docstring, int slots);
 | 
			
		||||
void py_newboundmethod(py_Ref out, py_Ref self, py_Ref func);
 | 
			
		||||
 | 
			
		||||
/************* Name Convertions *************/
 | 
			
		||||
py_Name py_name(const char*);
 | 
			
		||||
@ -121,7 +126,7 @@ void* py_newobject(py_Ref out, py_Type type, int slots, int udsize);
 | 
			
		||||
/************* Type Cast *************/
 | 
			
		||||
py_i64 py_toint(py_Ref);
 | 
			
		||||
py_f64 py_tofloat(py_Ref);
 | 
			
		||||
bool py_castfloat(py_Ref, py_f64* out);
 | 
			
		||||
bool py_castfloat(py_Ref, py_f64* out) PY_RAISE;
 | 
			
		||||
bool py_tobool(py_Ref);
 | 
			
		||||
py_Type py_totype(py_Ref);
 | 
			
		||||
const char* py_tostr(py_Ref);
 | 
			
		||||
@ -186,6 +191,7 @@ py_GlobalRef py_retval();
 | 
			
		||||
py_ObjectRef py_getdict(py_Ref self, py_Name name);
 | 
			
		||||
void py_setdict(py_Ref self, py_Name name, py_Ref val);
 | 
			
		||||
bool py_deldict(py_Ref self, py_Name name);
 | 
			
		||||
py_ObjectRef py_emplacedict(py_Ref self, py_Name name);
 | 
			
		||||
 | 
			
		||||
/// Get the reference of the i-th slot of the object.
 | 
			
		||||
/// The object must have slots and `i` must be in range.
 | 
			
		||||
@ -198,6 +204,7 @@ void py_bind(py_Ref obj, const char* sig, py_CFunction f);
 | 
			
		||||
// old style argc-based bindings
 | 
			
		||||
void py_bindmethod(py_Type type, const char* name, py_CFunction f);
 | 
			
		||||
void py_bindfunc(py_Ref obj, const char* name, py_CFunction f);
 | 
			
		||||
void py_bindproperty(py_Type type, const char* name, py_CFunction getter, py_CFunction setter);
 | 
			
		||||
 | 
			
		||||
#define py_bindmagic(type, __magic__, f) py_newnativefunc(py_tpmagic((type), __magic__), (f))
 | 
			
		||||
 | 
			
		||||
@ -257,6 +264,11 @@ py_StackRef py_pushtmp();
 | 
			
		||||
/// If returns true:  [self] -> [unbound, self]
 | 
			
		||||
/// If returns false: [self] -> [self] (no change)
 | 
			
		||||
bool py_pushmethod(py_Name name);
 | 
			
		||||
/// A stack operation that calls a function.
 | 
			
		||||
/// It assumes `argc + kwargc` arguments are already pushed to the stack.
 | 
			
		||||
/// The result will be set to `py_retval()`.
 | 
			
		||||
/// The stack size will be reduced by `argc + kwargc`.
 | 
			
		||||
bool py_vectorcall(uint16_t argc, uint16_t kwargc) PY_RAISE;
 | 
			
		||||
 | 
			
		||||
/************* Modules *************/
 | 
			
		||||
py_TmpRef py_newmodule(const char* path);
 | 
			
		||||
@ -264,20 +276,25 @@ py_TmpRef py_getmodule(const char* path);
 | 
			
		||||
 | 
			
		||||
/// Import a module.
 | 
			
		||||
/// The result will be set to `py_retval()`.
 | 
			
		||||
bool py_import(const char* path) PY_RAISE;
 | 
			
		||||
/// -1: error, 0: not found, 1: success
 | 
			
		||||
int py_import(const char* path) PY_RAISE;
 | 
			
		||||
 | 
			
		||||
/************* Errors *************/
 | 
			
		||||
/// Raise an exception by name and message. Always returns false.
 | 
			
		||||
bool py_exception(const char* name, const char* fmt, ...) PY_RAISE;
 | 
			
		||||
/// Raise an expection object. Always returns false.
 | 
			
		||||
bool py_raise(py_Ref) PY_RAISE;
 | 
			
		||||
/// Print the last error to the console.
 | 
			
		||||
/// Print the current exception.
 | 
			
		||||
void py_printexc();
 | 
			
		||||
/// Format the last error to a string.
 | 
			
		||||
/// Format the current exception.
 | 
			
		||||
char* py_formatexc();
 | 
			
		||||
/// Check if an exception is raised.
 | 
			
		||||
bool py_checkexc();
 | 
			
		||||
/// Clear the current exception.
 | 
			
		||||
void py_clearexc(py_StackRef p0);
 | 
			
		||||
 | 
			
		||||
#define IOError(...) py_exception("IOError", __VA_ARGS__)
 | 
			
		||||
#define OSError(...) py_exception("OSError", __VA_ARGS__)
 | 
			
		||||
#define NameError(n) py_exception("NameError", "name '%n' is not defined", (n))
 | 
			
		||||
#define TypeError(...) py_exception("TypeError", __VA_ARGS__)
 | 
			
		||||
#define RuntimeError(...) py_exception("RuntimeError", __VA_ARGS__)
 | 
			
		||||
@ -317,11 +334,6 @@ bool py_iter(py_Ref) PY_RAISE;
 | 
			
		||||
int py_next(py_Ref) PY_RAISE;
 | 
			
		||||
/// Python equivalent to `lhs is rhs`.
 | 
			
		||||
bool py_isidentical(py_Ref, py_Ref);
 | 
			
		||||
/// A stack operation that calls a function.
 | 
			
		||||
/// It assumes `argc + kwargc` arguments are already pushed to the stack.
 | 
			
		||||
/// The result will be set to `py_retval()`.
 | 
			
		||||
/// The stack size will be reduced by `argc + kwargc`.
 | 
			
		||||
bool py_vectorcall(uint16_t argc, uint16_t kwargc) PY_RAISE;
 | 
			
		||||
/// Call a function.
 | 
			
		||||
/// It prepares the stack and then performs a `vectorcall(argc, 0, false)`.
 | 
			
		||||
/// The result will be set to `py_retval()`.
 | 
			
		||||
@ -360,13 +372,8 @@ bool py_dict__contains(py_Ref self, py_Ref key);
 | 
			
		||||
int py_dict__len(py_Ref self);
 | 
			
		||||
bool py_dict__apply(py_Ref self, bool (*f)(py_Ref key, py_Ref val, void* ctx), void* ctx);
 | 
			
		||||
 | 
			
		||||
/************* Virtual File System *************/
 | 
			
		||||
unsigned char* py_vfsread(const char* path, int* size);
 | 
			
		||||
bool py_vfswrite(const char* path, unsigned char* data, int size);
 | 
			
		||||
char** py_vfslist(const char* path, int* length);
 | 
			
		||||
 | 
			
		||||
/************* Others *************/
 | 
			
		||||
int py_replinput(char* buf);
 | 
			
		||||
int py_replinput(char* buf, int max_size);
 | 
			
		||||
 | 
			
		||||
/// Python favored string formatting. (just put here, not for users)
 | 
			
		||||
/// %d: int
 | 
			
		||||
 | 
			
		||||
@ -56,7 +56,6 @@ MAGIC_METHOD(__exit__)
 | 
			
		||||
MAGIC_METHOD(__name__)
 | 
			
		||||
MAGIC_METHOD(__all__)
 | 
			
		||||
MAGIC_METHOD(__package__)
 | 
			
		||||
MAGIC_METHOD(__module_is_pending__)
 | 
			
		||||
MAGIC_METHOD(__path__)
 | 
			
		||||
MAGIC_METHOD(__class__)
 | 
			
		||||
MAGIC_METHOD(__abs__)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								prebuild.py
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								prebuild.py
									
									
									
									
									
								
							@ -31,6 +31,8 @@ with open("include/pocketpy/common/_generated.h", "wt", encoding='utf-8', newlin
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
const char* load_kPythonLib(const char* name);
 | 
			
		||||
 | 
			
		||||
'''
 | 
			
		||||
    for key in sorted(sources.keys()):
 | 
			
		||||
        value = sources[key]
 | 
			
		||||
@ -45,9 +47,20 @@ extern "C" {
 | 
			
		||||
with open("src/common/_generated.c", "wt", encoding='utf-8', newline='\n') as f:
 | 
			
		||||
    data = '''// generated by prebuild.py
 | 
			
		||||
#include "pocketpy/common/_generated.h"
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
'''
 | 
			
		||||
    for key in sorted(sources.keys()):
 | 
			
		||||
        value = sources[key]
 | 
			
		||||
        data += f'const char kPythonLibs_{key}[] = {value};\n'
 | 
			
		||||
    f.write(data)
 | 
			
		||||
 | 
			
		||||
    f.write("\n")
 | 
			
		||||
    f.write("const char* load_kPythonLib(const char* name) {\n")
 | 
			
		||||
    f.write("    if (strchr(name, '.') != NULL) return NULL;\n")
 | 
			
		||||
    for key in sorted(sources.keys()):
 | 
			
		||||
        if key.startswith('_'):
 | 
			
		||||
            continue
 | 
			
		||||
        f.write(f'    if (strcmp(name, "{key}") == 0) return kPythonLibs_{key};\n')
 | 
			
		||||
    f.write("    return NULL;\n")
 | 
			
		||||
    f.write("}\n")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,3 @@
 | 
			
		||||
from pkpy import next
 | 
			
		||||
 | 
			
		||||
class cache:
 | 
			
		||||
    def __init__(self, f):
 | 
			
		||||
        self.f = f
 | 
			
		||||
@ -13,9 +11,10 @@ class cache:
 | 
			
		||||
def reduce(function, sequence, initial=...):
 | 
			
		||||
    it = iter(sequence)
 | 
			
		||||
    if initial is ...:
 | 
			
		||||
        value = next(it)
 | 
			
		||||
        if value is StopIteration:
 | 
			
		||||
            raise TypeError("reduce() of empty iterable with no initial value")
 | 
			
		||||
        try:
 | 
			
		||||
            value = next(it)
 | 
			
		||||
        except StopIteration:
 | 
			
		||||
            raise TypeError("reduce() of empty sequence with no initial value")
 | 
			
		||||
    else:
 | 
			
		||||
        value = initial
 | 
			
		||||
    for element in it:
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -242,13 +242,13 @@ static FixedMemoryPool PoolExpr;
 | 
			
		||||
static FixedMemoryPool PoolFrame;
 | 
			
		||||
static MemoryPool PoolObject;
 | 
			
		||||
 | 
			
		||||
void pk_MemoryPools__initialize(){
 | 
			
		||||
void MemoryPools__initialize(){
 | 
			
		||||
    FixedMemoryPool__ctor(&PoolExpr, kPoolExprBlockSize, 64);
 | 
			
		||||
    FixedMemoryPool__ctor(&PoolFrame, kPoolFrameBlockSize, 128);
 | 
			
		||||
    MemoryPool__ctor(&PoolObject);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pk_MemoryPools__finalize(){
 | 
			
		||||
void MemoryPools__finalize(){
 | 
			
		||||
    FixedMemoryPool__dtor(&PoolExpr);
 | 
			
		||||
    FixedMemoryPool__dtor(&PoolFrame);
 | 
			
		||||
    MemoryPool__dtor(&PoolObject);
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,7 @@
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
static void pk_SourceData__ctor(struct pk_SourceData* self,
 | 
			
		||||
static void SourceData__ctor(struct SourceData* self,
 | 
			
		||||
                                const char* source,
 | 
			
		||||
                                const char* filename,
 | 
			
		||||
                                enum py_CompileMode mode,
 | 
			
		||||
@ -31,7 +31,7 @@ static void pk_SourceData__ctor(struct pk_SourceData* self,
 | 
			
		||||
    c11_vector__push(const char*, &self->line_starts, self->source->data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pk_SourceData__dtor(struct pk_SourceData* self) {
 | 
			
		||||
static void SourceData__dtor(struct SourceData* self) {
 | 
			
		||||
    c11_string__delete(self->filename);
 | 
			
		||||
    c11_string__delete(self->source);
 | 
			
		||||
 | 
			
		||||
@ -43,18 +43,18 @@ static void pk_SourceData__dtor(struct pk_SourceData* self) {
 | 
			
		||||
    c11_vector__dtor(&self->_precompiled_tokens);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pk_SourceData_ pk_SourceData__rcnew(const char* source,
 | 
			
		||||
SourceData_ SourceData__rcnew(const char* source,
 | 
			
		||||
                                    const char* filename,
 | 
			
		||||
                                    enum py_CompileMode mode,
 | 
			
		||||
                                    bool is_dynamic) {
 | 
			
		||||
    pk_SourceData_ self = malloc(sizeof(struct pk_SourceData));
 | 
			
		||||
    pk_SourceData__ctor(self, source, filename, mode, is_dynamic);
 | 
			
		||||
    SourceData_ self = malloc(sizeof(struct SourceData));
 | 
			
		||||
    SourceData__ctor(self, source, filename, mode, is_dynamic);
 | 
			
		||||
    self->rc.count = 1;
 | 
			
		||||
    self->rc.dtor = (void (*)(void*))pk_SourceData__dtor;
 | 
			
		||||
    self->rc.dtor = (void (*)(void*))SourceData__dtor;
 | 
			
		||||
    return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool pk_SourceData__get_line(const struct pk_SourceData* self,
 | 
			
		||||
bool SourceData__get_line(const struct SourceData* self,
 | 
			
		||||
                             int lineno,
 | 
			
		||||
                             const char** st,
 | 
			
		||||
                             const char** ed) {
 | 
			
		||||
@ -71,7 +71,7 @@ bool pk_SourceData__get_line(const struct pk_SourceData* self,
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pk_SourceData__snapshot(const struct pk_SourceData* self,
 | 
			
		||||
void SourceData__snapshot(const struct SourceData* self,
 | 
			
		||||
                             c11_sbuf* ss,
 | 
			
		||||
                             int lineno,
 | 
			
		||||
                             const char* cursor,
 | 
			
		||||
@ -86,7 +86,7 @@ void pk_SourceData__snapshot(const struct pk_SourceData* self,
 | 
			
		||||
    if(!self->is_precompiled) {
 | 
			
		||||
        c11_sbuf__write_char(ss, '\n');
 | 
			
		||||
        const char *st = NULL, *ed;
 | 
			
		||||
        if(pk_SourceData__get_line(self, lineno, &st, &ed)) {
 | 
			
		||||
        if(SourceData__get_line(self, lineno, &st, &ed)) {
 | 
			
		||||
            while(st < ed && isblank(*st))
 | 
			
		||||
                ++st;
 | 
			
		||||
            if(st < ed) {
 | 
			
		||||
 | 
			
		||||
@ -147,7 +147,7 @@ c11_string* c11_sbuf__submit(c11_sbuf* self) {
 | 
			
		||||
    return retval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void c11_sbuf__py_submit(c11_sbuf *self, py_Ref out){
 | 
			
		||||
void c11_sbuf__py_submit(c11_sbuf* self, py_Ref out) {
 | 
			
		||||
    c11_string* res = c11_sbuf__submit(self);
 | 
			
		||||
    py_newstrn(out, res->data, res->size);
 | 
			
		||||
    c11_string__delete(res);
 | 
			
		||||
@ -233,7 +233,9 @@ void pk_sprintf(c11_sbuf* ss, const char* fmt, ...) {
 | 
			
		||||
    va_end(args);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int py_replinput(char* buf) {
 | 
			
		||||
int py_replinput(char* buf, int max_size) {
 | 
			
		||||
    buf[0] = '\0';
 | 
			
		||||
 | 
			
		||||
    int size = 0;
 | 
			
		||||
    bool multiline = false;
 | 
			
		||||
    printf(">>> ");
 | 
			
		||||
@ -252,7 +254,7 @@ int py_replinput(char* buf) {
 | 
			
		||||
                    printf("... ");
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                if(last == ':' || last == '(' || last == '[' || last == '{') {
 | 
			
		||||
                if(last == ':' || last == '(' || last == '[' || last == '{' || buf[0] == '@') {
 | 
			
		||||
                    printf("... ");
 | 
			
		||||
                    multiline = true;
 | 
			
		||||
                } else {
 | 
			
		||||
@ -261,6 +263,11 @@ int py_replinput(char* buf) {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(size == max_size - 1) {
 | 
			
		||||
            buf[size] = '\0';
 | 
			
		||||
            return size;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        buf[size++] = c;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -165,6 +165,16 @@ int c11_sv__count(c11_sv self, c11_sv sub) {
 | 
			
		||||
    return cnt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool c11_sv__startswith(c11_sv self, c11_sv prefix) {
 | 
			
		||||
    if(prefix.size > self.size) return false;
 | 
			
		||||
    return memcmp(self.data, prefix.data, prefix.size) == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool c11_sv__endswith(c11_sv self, c11_sv suffix) {
 | 
			
		||||
    if(suffix.size > self.size) return false;
 | 
			
		||||
    return memcmp(self.data + self.size - suffix.size, suffix.data, suffix.size) == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
c11_vector /* T=c11_sv */ c11_sv__split(c11_sv self, char sep) {
 | 
			
		||||
    c11_vector retval;
 | 
			
		||||
    c11_vector__ctor(&retval, sizeof(c11_sv));
 | 
			
		||||
 | 
			
		||||
@ -1435,13 +1435,13 @@ typedef struct PrattRule {
 | 
			
		||||
const static PrattRule rules[TK__COUNT__];
 | 
			
		||||
 | 
			
		||||
typedef struct Compiler {
 | 
			
		||||
    pk_SourceData_ src;  // weakref
 | 
			
		||||
    pk_TokenArray tokens;
 | 
			
		||||
    SourceData_ src;  // weakref
 | 
			
		||||
    TokenArray tokens;
 | 
			
		||||
    int i;
 | 
			
		||||
    c11_vector /*T=CodeEmitContext*/ contexts;
 | 
			
		||||
} Compiler;
 | 
			
		||||
 | 
			
		||||
static void Compiler__ctor(Compiler* self, pk_SourceData_ src, pk_TokenArray tokens) {
 | 
			
		||||
static void Compiler__ctor(Compiler* self, SourceData_ src, TokenArray tokens) {
 | 
			
		||||
    self->src = src;
 | 
			
		||||
    self->tokens = tokens;
 | 
			
		||||
    self->i = 0;
 | 
			
		||||
@ -1449,7 +1449,7 @@ static void Compiler__ctor(Compiler* self, pk_SourceData_ src, pk_TokenArray tok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void Compiler__dtor(Compiler* self) {
 | 
			
		||||
    pk_TokenArray__dtor(&self->tokens);
 | 
			
		||||
    TokenArray__dtor(&self->tokens);
 | 
			
		||||
    c11__foreach(Ctx, &self->contexts, ctx) Ctx__dtor(ctx);
 | 
			
		||||
    c11_vector__dtor(&self->contexts);
 | 
			
		||||
}
 | 
			
		||||
@ -1470,8 +1470,8 @@ static void Compiler__dtor(Compiler* self) {
 | 
			
		||||
    if(!match(expected))                                                                           \
 | 
			
		||||
        return SyntaxError(self,                                                                   \
 | 
			
		||||
                           "expected '%s', got '%s'",                                              \
 | 
			
		||||
                           pk_TokenSymbols[expected],                                              \
 | 
			
		||||
                           pk_TokenSymbols[curr()->type]);
 | 
			
		||||
                           TokenSymbols[expected],                                              \
 | 
			
		||||
                           TokenSymbols[curr()->type]);
 | 
			
		||||
#define consume_end_stmt()                                                                         \
 | 
			
		||||
    if(!match_end_stmt(self)) return SyntaxError(self, "expected statement end")
 | 
			
		||||
 | 
			
		||||
@ -1531,7 +1531,7 @@ static bool match_end_stmt(Compiler* self) {
 | 
			
		||||
static Error* parse_expression(Compiler* self, int precedence, bool allow_slice) {
 | 
			
		||||
    PrattCallback prefix = rules[curr()->type].prefix;
 | 
			
		||||
    if(!prefix || (curr()->type == TK_COLON && !allow_slice)) {
 | 
			
		||||
        return SyntaxError(self, "expected an expression, got %s", pk_TokenSymbols[curr()->type]);
 | 
			
		||||
        return SyntaxError(self, "expected an expression, got %s", TokenSymbols[curr()->type]);
 | 
			
		||||
    }
 | 
			
		||||
    advance();
 | 
			
		||||
    Error* err;
 | 
			
		||||
@ -2477,6 +2477,7 @@ __EAT_DOTS_END:
 | 
			
		||||
               OP_IMPORT_PATH,
 | 
			
		||||
               Ctx__add_const_string(ctx(), c11_string__sv(path)),
 | 
			
		||||
               prev()->line);
 | 
			
		||||
    c11_string__delete(path);
 | 
			
		||||
    consume(TK_IMPORT);
 | 
			
		||||
 | 
			
		||||
    if(match(TK_MUL)) {
 | 
			
		||||
@ -2781,9 +2782,9 @@ Error* Compiler__compile(Compiler* self, CodeObject* out) {
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Error* pk_compile(pk_SourceData_ src, CodeObject* out) {
 | 
			
		||||
    pk_TokenArray tokens;
 | 
			
		||||
    Error* err = pk_Lexer__process(src, &tokens);
 | 
			
		||||
Error* pk_compile(SourceData_ src, CodeObject* out) {
 | 
			
		||||
    TokenArray tokens;
 | 
			
		||||
    Error* err = Lexer__process(src, &tokens);
 | 
			
		||||
    if(err) return err;
 | 
			
		||||
 | 
			
		||||
    // Token* data = (Token*)tokens.data;
 | 
			
		||||
@ -2791,7 +2792,7 @@ Error* pk_compile(pk_SourceData_ src, CodeObject* out) {
 | 
			
		||||
    // for(int i = 0; i < tokens.count; i++) {
 | 
			
		||||
    //     Token* t = data + i;
 | 
			
		||||
    //     c11_string* tmp = c11_string__new2(t->start, t->length);
 | 
			
		||||
    //     printf("[%d] %s: %s\n", t->line, pk_TokenSymbols[t->type], tmp->data);
 | 
			
		||||
    //     printf("[%d] %s: %s\n", t->line, TokenSymbols[t->type], tmp->data);
 | 
			
		||||
    //     c11_string__delete(tmp);
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -10,8 +10,8 @@
 | 
			
		||||
 | 
			
		||||
#define is_raw_string_used(t) ((t) == TK_ID || (t) == TK_LONG)
 | 
			
		||||
 | 
			
		||||
typedef struct pk_Lexer{
 | 
			
		||||
    pk_SourceData_ src;
 | 
			
		||||
typedef struct Lexer{
 | 
			
		||||
    SourceData_ src;
 | 
			
		||||
    const char* token_start;
 | 
			
		||||
    const char* curr_char;
 | 
			
		||||
    int current_line;
 | 
			
		||||
@ -19,7 +19,7 @@ typedef struct pk_Lexer{
 | 
			
		||||
 | 
			
		||||
    c11_vector/*T=Token*/ nexts;
 | 
			
		||||
    c11_vector/*T=int*/ indents;
 | 
			
		||||
} pk_Lexer;
 | 
			
		||||
} Lexer;
 | 
			
		||||
 | 
			
		||||
typedef struct TokenDeserializer {
 | 
			
		||||
    const char* curr;
 | 
			
		||||
@ -37,7 +37,7 @@ double TokenDeserializer__read_float(TokenDeserializer* self, char c);
 | 
			
		||||
 | 
			
		||||
const static TokenValue EmptyTokenValue;
 | 
			
		||||
 | 
			
		||||
static void pk_Lexer__ctor(pk_Lexer* self, pk_SourceData_ src){
 | 
			
		||||
static void Lexer__ctor(Lexer* self, SourceData_ src){
 | 
			
		||||
    PK_INCREF(src);
 | 
			
		||||
    self->src = src;
 | 
			
		||||
    self->curr_char = self->token_start = src->source->data;
 | 
			
		||||
@ -47,20 +47,20 @@ static void pk_Lexer__ctor(pk_Lexer* self, pk_SourceData_ src){
 | 
			
		||||
    c11_vector__ctor(&self->indents, sizeof(int));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pk_Lexer__dtor(pk_Lexer* self){
 | 
			
		||||
static void Lexer__dtor(Lexer* self){
 | 
			
		||||
    PK_DECREF(self->src);
 | 
			
		||||
    c11_vector__dtor(&self->nexts);
 | 
			
		||||
    c11_vector__dtor(&self->indents);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char eatchar(pk_Lexer* self){
 | 
			
		||||
static char eatchar(Lexer* self){
 | 
			
		||||
    char c = *self->curr_char;
 | 
			
		||||
    assert(c != '\n');  // eatchar() cannot consume a newline
 | 
			
		||||
    self->curr_char++;
 | 
			
		||||
    return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char eatchar_include_newline(pk_Lexer* self){
 | 
			
		||||
static char eatchar_include_newline(Lexer* self){
 | 
			
		||||
    char c = *self->curr_char;
 | 
			
		||||
    self->curr_char++;
 | 
			
		||||
    if(c == '\n') {
 | 
			
		||||
@ -70,7 +70,7 @@ static char eatchar_include_newline(pk_Lexer* self){
 | 
			
		||||
    return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int eat_spaces(pk_Lexer* self){
 | 
			
		||||
static int eat_spaces(Lexer* self){
 | 
			
		||||
    int count = 0;
 | 
			
		||||
    while(true) {
 | 
			
		||||
        switch(*self->curr_char) {
 | 
			
		||||
@ -82,13 +82,13 @@ static int eat_spaces(pk_Lexer* self){
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool matchchar(pk_Lexer* self, char c){
 | 
			
		||||
static bool matchchar(Lexer* self, char c){
 | 
			
		||||
    if(*self->curr_char != c) return false;
 | 
			
		||||
    eatchar_include_newline(self);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool match_n_chars(pk_Lexer* self, int n, char c0){
 | 
			
		||||
static bool match_n_chars(Lexer* self, int n, char c0){
 | 
			
		||||
    const char* c = self->curr_char;
 | 
			
		||||
    for(int i = 0; i < n; i++) {
 | 
			
		||||
        if(*c == '\0') return false;
 | 
			
		||||
@ -100,14 +100,14 @@ static bool match_n_chars(pk_Lexer* self, int n, char c0){
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void skip_line_comment(pk_Lexer* self){
 | 
			
		||||
static void skip_line_comment(Lexer* self){
 | 
			
		||||
    while(*self->curr_char) {
 | 
			
		||||
        if(*self->curr_char == '\n') return;
 | 
			
		||||
        eatchar(self);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void add_token_with_value(pk_Lexer* self, TokenIndex type, TokenValue value){
 | 
			
		||||
static void add_token_with_value(Lexer* self, TokenIndex type, TokenValue value){
 | 
			
		||||
    switch(type) {
 | 
			
		||||
        case TK_LBRACE:
 | 
			
		||||
        case TK_LBRACKET:
 | 
			
		||||
@ -142,18 +142,18 @@ static void add_token_with_value(pk_Lexer* self, TokenIndex type, TokenValue val
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void add_token(pk_Lexer* self, TokenIndex type){
 | 
			
		||||
static void add_token(Lexer* self, TokenIndex type){
 | 
			
		||||
    add_token_with_value(self, type, EmptyTokenValue);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void add_token_2(pk_Lexer* self, char c, TokenIndex one, TokenIndex two){
 | 
			
		||||
static void add_token_2(Lexer* self, char c, TokenIndex one, TokenIndex two){
 | 
			
		||||
    if(matchchar(self, c))
 | 
			
		||||
        add_token(self, two);
 | 
			
		||||
    else
 | 
			
		||||
        add_token(self, one);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool eat_indentation(pk_Lexer* self){
 | 
			
		||||
static bool eat_indentation(Lexer* self){
 | 
			
		||||
    if(self->brackets_level > 0) return true;
 | 
			
		||||
    int spaces = eat_spaces(self);
 | 
			
		||||
    if(*self->curr_char == '#') skip_line_comment(self);
 | 
			
		||||
@ -192,7 +192,7 @@ static bool is_possible_number_char(char c){
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************/
 | 
			
		||||
static Error* SyntaxError(pk_Lexer* self, const char* fmt, ...){
 | 
			
		||||
static Error* SyntaxError(Lexer* self, const char* fmt, ...){
 | 
			
		||||
    Error* err = malloc(sizeof(Error));
 | 
			
		||||
    err->src = self->src;
 | 
			
		||||
    PK_INCREF(self->src);
 | 
			
		||||
@ -207,7 +207,7 @@ static Error* SyntaxError(pk_Lexer* self, const char* fmt, ...){
 | 
			
		||||
    return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Error* eat_name(pk_Lexer* self){
 | 
			
		||||
static Error* eat_name(Lexer* self){
 | 
			
		||||
    self->curr_char--;
 | 
			
		||||
    while(true) {
 | 
			
		||||
        unsigned char c = *self->curr_char;
 | 
			
		||||
@ -247,7 +247,7 @@ static Error* eat_name(pk_Lexer* self){
 | 
			
		||||
    if(length == 0) return SyntaxError(self, "@id contains invalid char");
 | 
			
		||||
    c11_sv name = {self->token_start, length};
 | 
			
		||||
 | 
			
		||||
    const char** KW_BEGIN = pk_TokenSymbols + TK_FALSE;
 | 
			
		||||
    const char** KW_BEGIN = TokenSymbols + TK_FALSE;
 | 
			
		||||
    int KW_COUNT = TK__COUNT__ - TK_FALSE;
 | 
			
		||||
    #define less(a, b) (c11_sv__cmp2(b, a) > 0)
 | 
			
		||||
    int out;
 | 
			
		||||
@ -262,7 +262,7 @@ static Error* eat_name(pk_Lexer* self){
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Error* eat_string_until(pk_Lexer* self, char quote, bool raw, c11_string** out) {
 | 
			
		||||
static Error* eat_string_until(Lexer* self, char quote, bool raw, c11_string** out) {
 | 
			
		||||
    // previous char is quote
 | 
			
		||||
    bool quote3 = match_n_chars(self, 2, quote);
 | 
			
		||||
    c11_sbuf buff;
 | 
			
		||||
@ -321,7 +321,7 @@ enum StringType {
 | 
			
		||||
    NORMAL_BYTES
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static Error* eat_string(pk_Lexer* self, char quote, enum StringType type){
 | 
			
		||||
static Error* eat_string(Lexer* self, char quote, enum StringType type){
 | 
			
		||||
    c11_string* s;
 | 
			
		||||
    Error* err = eat_string_until(self, quote, type == RAW_STRING, &s);
 | 
			
		||||
    if(err) return err;
 | 
			
		||||
@ -336,7 +336,7 @@ static Error* eat_string(pk_Lexer* self, char quote, enum StringType type){
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Error* eat_number(pk_Lexer* self){
 | 
			
		||||
static Error* eat_number(Lexer* self){
 | 
			
		||||
    const char* i = self->token_start;
 | 
			
		||||
    while(is_possible_number_char(*i)) i++;
 | 
			
		||||
 | 
			
		||||
@ -389,7 +389,7 @@ static Error* eat_number(pk_Lexer* self){
 | 
			
		||||
    return SyntaxError(self, "invalid number literal");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Error* lex_one_token(pk_Lexer* self, bool* eof){
 | 
			
		||||
static Error* lex_one_token(Lexer* self, bool* eof){
 | 
			
		||||
    *eof = false;
 | 
			
		||||
    while(*self->curr_char) {
 | 
			
		||||
        self->token_start = self->curr_char;
 | 
			
		||||
@ -532,7 +532,7 @@ static Error* lex_one_token(pk_Lexer* self, bool* eof){
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Error* from_precompiled(pk_Lexer* self) {
 | 
			
		||||
static Error* from_precompiled(Lexer* self) {
 | 
			
		||||
    TokenDeserializer deserializer;
 | 
			
		||||
    TokenDeserializer__ctor(&deserializer, self->src->source->data);
 | 
			
		||||
 | 
			
		||||
@ -603,14 +603,14 @@ static Error* from_precompiled(pk_Lexer* self) {
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Error* pk_Lexer__process(pk_SourceData_ src, pk_TokenArray* out_tokens){
 | 
			
		||||
    pk_Lexer lexer;
 | 
			
		||||
    pk_Lexer__ctor(&lexer, src);
 | 
			
		||||
Error* Lexer__process(SourceData_ src, TokenArray* out_tokens){
 | 
			
		||||
    Lexer lexer;
 | 
			
		||||
    Lexer__ctor(&lexer, src);
 | 
			
		||||
 | 
			
		||||
    if(src->is_precompiled) {
 | 
			
		||||
        Error* err = from_precompiled(&lexer);
 | 
			
		||||
        // TODO: set out tokens
 | 
			
		||||
        pk_Lexer__dtor(&lexer);
 | 
			
		||||
        Lexer__dtor(&lexer);
 | 
			
		||||
        return err;
 | 
			
		||||
    }
 | 
			
		||||
    // push initial tokens
 | 
			
		||||
@ -622,21 +622,21 @@ Error* pk_Lexer__process(pk_SourceData_ src, pk_TokenArray* out_tokens){
 | 
			
		||||
    while(!eof) {
 | 
			
		||||
        void* err = lex_one_token(&lexer, &eof);
 | 
			
		||||
        if(err){
 | 
			
		||||
            pk_Lexer__dtor(&lexer);
 | 
			
		||||
            Lexer__dtor(&lexer);
 | 
			
		||||
            return err;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // set out_tokens
 | 
			
		||||
    *out_tokens = c11_vector__submit(&lexer.nexts);
 | 
			
		||||
 | 
			
		||||
    pk_Lexer__dtor(&lexer);
 | 
			
		||||
    Lexer__dtor(&lexer);
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Error* pk_Lexer__process_and_dump(pk_SourceData_ src, c11_string** out) {
 | 
			
		||||
Error* Lexer__process_and_dump(SourceData_ src, c11_string** out) {
 | 
			
		||||
    assert(!src->is_precompiled);
 | 
			
		||||
    pk_TokenArray nexts;    // output tokens
 | 
			
		||||
    Error* err = pk_Lexer__process(src, &nexts);
 | 
			
		||||
    TokenArray nexts;    // output tokens
 | 
			
		||||
    Error* err = Lexer__process(src, &nexts);
 | 
			
		||||
    if(err) return err;
 | 
			
		||||
 | 
			
		||||
    c11_sbuf ss;
 | 
			
		||||
@ -729,7 +729,7 @@ Error* pk_Lexer__process_and_dump(pk_SourceData_ src, c11_string** out) {
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pk_TokenArray__dtor(pk_TokenArray *self){
 | 
			
		||||
void TokenArray__dtor(TokenArray *self){
 | 
			
		||||
    Token* data = self->data;
 | 
			
		||||
    for(int i=0; i<self->count; i++){
 | 
			
		||||
        if(data[i].value.index == TokenValue_STR){
 | 
			
		||||
@ -739,7 +739,7 @@ void pk_TokenArray__dtor(pk_TokenArray *self){
 | 
			
		||||
    c11_array__dtor(self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char* pk_TokenSymbols[] = {
 | 
			
		||||
const char* TokenSymbols[] = {
 | 
			
		||||
    "@eof", "@eol", "@sof",
 | 
			
		||||
    "@id", "@num", "@str", "@fstr", "@long", "@bytes", "@imag",
 | 
			
		||||
    "@indent", "@dedent",
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@
 | 
			
		||||
#include "pocketpy/objects/error.h"
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
static bool stack_unpack_sequence(pk_VM* self, uint16_t arg);
 | 
			
		||||
static bool stack_unpack_sequence(VM* self, uint16_t arg);
 | 
			
		||||
static bool format_object(py_Ref obj, c11_sv spec);
 | 
			
		||||
 | 
			
		||||
#define DISPATCH()                                                                                 \
 | 
			
		||||
@ -54,7 +54,7 @@ static bool format_object(py_Ref obj, c11_sv spec);
 | 
			
		||||
 | 
			
		||||
#define vectorcall_opcall(argc, kwargc)                                                            \
 | 
			
		||||
    do {                                                                                           \
 | 
			
		||||
        pk_FrameResult res = pk_VM__vectorcall(self, (argc), (kwargc), true);                      \
 | 
			
		||||
        FrameResult res = VM__vectorcall(self, (argc), (kwargc), true);                      \
 | 
			
		||||
        switch(res) {                                                                              \
 | 
			
		||||
            case RES_RETURN: PUSH(&self->last_retval); break;                                      \
 | 
			
		||||
            case RES_CALL: frame = self->top_frame; goto __NEXT_FRAME;                             \
 | 
			
		||||
@ -75,7 +75,7 @@ static bool unpack_dict_to_buffer(py_Ref key, py_Ref val, void* ctx) {
 | 
			
		||||
    return TypeError("keywords must be strings, not '%t'", key->type);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
 | 
			
		||||
FrameResult VM__run_top_frame(VM* self) {
 | 
			
		||||
    Frame* frame = self->top_frame;
 | 
			
		||||
    const Frame* base_frame = frame;
 | 
			
		||||
 | 
			
		||||
@ -139,7 +139,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
 | 
			
		||||
                    ud->closure = FastLocals__to_namedict(frame->locals, frame->locals_co);
 | 
			
		||||
                    py_Name name = py_namev(c11_string__sv(decl->code.name));
 | 
			
		||||
                    // capture itself to allow recursion
 | 
			
		||||
                    pk_NameDict__set(ud->closure, name, *SP());
 | 
			
		||||
                    NameDict__set(ud->closure, name, *SP());
 | 
			
		||||
                }
 | 
			
		||||
                SP()++;
 | 
			
		||||
                DISPATCH();
 | 
			
		||||
@ -257,6 +257,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
 | 
			
		||||
                    // fallback to getattr
 | 
			
		||||
                    if(py_getattr(TOP(), byte.arg)) {
 | 
			
		||||
                        py_assign(TOP(), py_retval());
 | 
			
		||||
                        py_newnil(SP()++);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        goto __ERROR;
 | 
			
		||||
                    }
 | 
			
		||||
@ -618,7 +619,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
 | 
			
		||||
                DISPATCH();
 | 
			
		||||
            }
 | 
			
		||||
            case OP_CALL: {
 | 
			
		||||
                pk_ManagedHeap__collect_if_needed(&self->heap);
 | 
			
		||||
                ManagedHeap__collect_if_needed(&self->heap);
 | 
			
		||||
                vectorcall_opcall(byte.arg & 0xFF, byte.arg >> 8);
 | 
			
		||||
                DISPATCH();
 | 
			
		||||
            }
 | 
			
		||||
@ -683,7 +684,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
 | 
			
		||||
                } else {
 | 
			
		||||
                    py_newnone(&self->last_retval);
 | 
			
		||||
                }
 | 
			
		||||
                pk_VM__pop_frame(self);
 | 
			
		||||
                VM__pop_frame(self);
 | 
			
		||||
                if(frame == base_frame) {  // [ frameBase<- ]
 | 
			
		||||
                    return RES_RETURN;
 | 
			
		||||
                } else {
 | 
			
		||||
@ -757,15 +758,20 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
 | 
			
		||||
            ////////
 | 
			
		||||
            case OP_IMPORT_PATH: {
 | 
			
		||||
                py_Ref path_object = c11__at(py_TValue, &frame->co->consts, byte.arg);
 | 
			
		||||
                bool ok = py_import(py_tostr(path_object));
 | 
			
		||||
                if(!ok) goto __ERROR;
 | 
			
		||||
                const char* path = py_tostr(path_object);
 | 
			
		||||
                int res = py_import(path);
 | 
			
		||||
                if(res == -1) goto __ERROR;
 | 
			
		||||
                if(res == 0) {
 | 
			
		||||
                    ImportError("module '%s' not found", path);
 | 
			
		||||
                    goto __ERROR;
 | 
			
		||||
                }
 | 
			
		||||
                PUSH(py_retval());
 | 
			
		||||
                DISPATCH();
 | 
			
		||||
            }
 | 
			
		||||
            case OP_POP_IMPORT_STAR: {
 | 
			
		||||
                // [module]
 | 
			
		||||
                pk_NameDict* dict = PyObject__dict(TOP()->_obj);
 | 
			
		||||
                py_Ref all = pk_NameDict__try_get(dict, __all__);
 | 
			
		||||
                NameDict* dict = PyObject__dict(TOP()->_obj);
 | 
			
		||||
                py_Ref all = NameDict__try_get(dict, __all__);
 | 
			
		||||
                if(all) {
 | 
			
		||||
                    int length;
 | 
			
		||||
                    py_TValue* p = pk_arrayview(all, &length);
 | 
			
		||||
@ -775,7 +781,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
 | 
			
		||||
                    }
 | 
			
		||||
                    for(int i = 0; i < length; i++) {
 | 
			
		||||
                        py_Name name = py_namev(py_tosv(p + i));
 | 
			
		||||
                        py_Ref value = pk_NameDict__try_get(dict, name);
 | 
			
		||||
                        py_Ref value = NameDict__try_get(dict, name);
 | 
			
		||||
                        if(value == NULL) {
 | 
			
		||||
                            ImportError("cannot import name '%n'", name);
 | 
			
		||||
                            goto __ERROR;
 | 
			
		||||
@ -785,7 +791,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    for(int i = 0; i < dict->count; i++) {
 | 
			
		||||
                        pk_NameDict_KV* kv = c11__at(pk_NameDict_KV, dict, i);
 | 
			
		||||
                        NameDict_KV* kv = c11__at(NameDict_KV, dict, i);
 | 
			
		||||
                        if(!kv->key) continue;
 | 
			
		||||
                        c11_sv name = py_name2sv(kv->key);
 | 
			
		||||
                        if(name.size == 0 || name.data[0] == '_') continue;
 | 
			
		||||
@ -848,10 +854,10 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
 | 
			
		||||
 | 
			
		||||
                if(py_istype(TOP(), tp_type)) {
 | 
			
		||||
                    // call on_end_subclass
 | 
			
		||||
                    pk_TypeInfo* ti = c11__at(pk_TypeInfo, &self->types, py_totype(TOP()));
 | 
			
		||||
                    py_TypeInfo* ti = c11__at(py_TypeInfo, &self->types, py_totype(TOP()));
 | 
			
		||||
                    if(ti->base != tp_object) {
 | 
			
		||||
                        // PyTypeInfo* base_ti = &_all_types[ti->base];
 | 
			
		||||
                        pk_TypeInfo* base_ti = c11__at(pk_TypeInfo, &self->types, ti->base);
 | 
			
		||||
                        py_TypeInfo* base_ti = c11__at(py_TypeInfo, &self->types, ti->base);
 | 
			
		||||
                        if(base_ti->on_end_subclass) base_ti->on_end_subclass(ti);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
@ -871,7 +877,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
 | 
			
		||||
            }
 | 
			
		||||
            case OP_ADD_CLASS_ANNOTATION: {
 | 
			
		||||
                py_Type type = py_totype(self->__curr_class);
 | 
			
		||||
                pk_TypeInfo* ti = c11__at(pk_TypeInfo, &self->types, type);
 | 
			
		||||
                py_TypeInfo* ti = c11__at(py_TypeInfo, &self->types, type);
 | 
			
		||||
                c11_vector__push(py_Name, &ti->annotated_fields, byte.arg);
 | 
			
		||||
                DISPATCH();
 | 
			
		||||
            }
 | 
			
		||||
@ -920,7 +926,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
 | 
			
		||||
            }
 | 
			
		||||
            case OP_POP_EXCEPTION: {
 | 
			
		||||
                assert(self->curr_exception.type);
 | 
			
		||||
                self->curr_exception = *py_NIL;
 | 
			
		||||
                py_clearexc(NULL);
 | 
			
		||||
                DISPATCH();
 | 
			
		||||
            }
 | 
			
		||||
            //////////////////
 | 
			
		||||
@ -964,7 +970,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
 | 
			
		||||
        } else {
 | 
			
		||||
            // 2. Exception need to be propagated to the upper frame
 | 
			
		||||
            bool is_base_frame_to_be_popped = frame == base_frame;
 | 
			
		||||
            pk_VM__pop_frame(self);
 | 
			
		||||
            VM__pop_frame(self);
 | 
			
		||||
            if(self->top_frame == NULL || is_base_frame_to_be_popped) {
 | 
			
		||||
                // propagate to the top level
 | 
			
		||||
                return RES_ERROR;
 | 
			
		||||
@ -977,7 +983,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
 | 
			
		||||
    return RES_RETURN;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool pk_stack_binaryop(pk_VM* self, py_Name op, py_Name rop) {
 | 
			
		||||
bool pk_stack_binaryop(VM* self, py_Name op, py_Name rop) {
 | 
			
		||||
    // [a, b]
 | 
			
		||||
    py_Ref magic = py_tpfindmagic(SECOND()->type, op);
 | 
			
		||||
    if(magic) {
 | 
			
		||||
@ -1008,7 +1014,7 @@ bool pk_stack_binaryop(pk_VM* self, py_Name op, py_Name rop) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) {
 | 
			
		||||
    pk_VM* self = pk_current_vm;
 | 
			
		||||
    VM* self = pk_current_vm;
 | 
			
		||||
    PUSH(lhs);
 | 
			
		||||
    PUSH(rhs);
 | 
			
		||||
    bool ok = pk_stack_binaryop(self, op, rop);
 | 
			
		||||
@ -1016,7 +1022,7 @@ bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) {
 | 
			
		||||
    return ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool stack_unpack_sequence(pk_VM* self, uint16_t arg) {
 | 
			
		||||
static bool stack_unpack_sequence(VM* self, uint16_t arg) {
 | 
			
		||||
    int length;
 | 
			
		||||
    py_TValue* p = pk_arrayview(TOP(), &length);
 | 
			
		||||
    if(!p) return TypeError("expected list or tuple to unpack, got '%t'", TOP()->type);
 | 
			
		||||
 | 
			
		||||
@ -14,11 +14,11 @@ py_TValue* FastLocals__try_get_by_name(py_TValue* locals, const CodeObject* co,
 | 
			
		||||
    return &locals[index];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pk_NameDict* FastLocals__to_namedict(py_TValue* locals, const CodeObject* co) {
 | 
			
		||||
    pk_NameDict* dict = pk_NameDict__new();
 | 
			
		||||
NameDict* FastLocals__to_namedict(py_TValue* locals, const CodeObject* co) {
 | 
			
		||||
    NameDict* dict = NameDict__new();
 | 
			
		||||
    c11__foreach(c11_smallmap_n2i_KV, &co->varnames_inv, entry) {
 | 
			
		||||
        py_TValue value = locals[entry->value];
 | 
			
		||||
        if(!py_isnil(&value)) { pk_NameDict__set(dict, entry->key, value); }
 | 
			
		||||
        if(!py_isnil(&value)) { NameDict__set(dict, entry->key, value); }
 | 
			
		||||
    }
 | 
			
		||||
    return dict;
 | 
			
		||||
}
 | 
			
		||||
@ -134,6 +134,6 @@ py_TValue* Frame__f_closure_try_get(Frame* self, py_Name name) {
 | 
			
		||||
    // if(self->function == NULL) return NULL;
 | 
			
		||||
    // pkpy::Function* fn = PyObject__as(pkpy::Function, self->function);
 | 
			
		||||
    // if(fn->_closure == nullptr) return nullptr;
 | 
			
		||||
    // return pk_NameDict__try_get(fn->_closure, name);
 | 
			
		||||
    // return NameDict__try_get(fn->_closure, name);
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
@ -2,7 +2,7 @@
 | 
			
		||||
#include "pocketpy/common/memorypool.h"
 | 
			
		||||
#include "pocketpy/objects/base.h"
 | 
			
		||||
 | 
			
		||||
void pk_ManagedHeap__ctor(pk_ManagedHeap *self, pk_VM *vm){
 | 
			
		||||
void ManagedHeap__ctor(ManagedHeap *self, VM *vm){
 | 
			
		||||
    c11_vector__ctor(&self->no_gc, sizeof(PyObject*));
 | 
			
		||||
    c11_vector__ctor(&self->gen, sizeof(PyObject*));
 | 
			
		||||
 | 
			
		||||
@ -13,7 +13,7 @@ void pk_ManagedHeap__ctor(pk_ManagedHeap *self, pk_VM *vm){
 | 
			
		||||
    self->gc_on_delete = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pk_ManagedHeap__dtor(pk_ManagedHeap *self){
 | 
			
		||||
void ManagedHeap__dtor(ManagedHeap *self){
 | 
			
		||||
    for(int i = 0; i < self->gen.count; i++){
 | 
			
		||||
        PyObject* obj = c11__getitem(PyObject*, &self->gen, i);
 | 
			
		||||
        PyObject__delete(obj);
 | 
			
		||||
@ -26,23 +26,23 @@ void pk_ManagedHeap__dtor(pk_ManagedHeap *self){
 | 
			
		||||
    c11_vector__dtor(&self->gen);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pk_ManagedHeap__collect_if_needed(pk_ManagedHeap *self){
 | 
			
		||||
void ManagedHeap__collect_if_needed(ManagedHeap *self){
 | 
			
		||||
    if(self->gc_counter < self->gc_threshold) return;
 | 
			
		||||
    self->gc_counter = 0;
 | 
			
		||||
    pk_ManagedHeap__collect(self);
 | 
			
		||||
    ManagedHeap__collect(self);
 | 
			
		||||
    self->gc_threshold = self->gen.count * 2;
 | 
			
		||||
    if(self->gc_threshold < PK_GC_MIN_THRESHOLD){
 | 
			
		||||
        self->gc_threshold = PK_GC_MIN_THRESHOLD;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int pk_ManagedHeap__collect(pk_ManagedHeap *self){
 | 
			
		||||
    pk_ManagedHeap__mark(self);
 | 
			
		||||
    int freed = pk_ManagedHeap__sweep(self);
 | 
			
		||||
int ManagedHeap__collect(ManagedHeap *self){
 | 
			
		||||
    ManagedHeap__mark(self);
 | 
			
		||||
    int freed = ManagedHeap__sweep(self);
 | 
			
		||||
    return freed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int pk_ManagedHeap__sweep(pk_ManagedHeap *self){
 | 
			
		||||
int ManagedHeap__sweep(ManagedHeap *self){
 | 
			
		||||
    c11_vector alive;
 | 
			
		||||
    c11_vector__ctor(&alive, sizeof(PyObject*));
 | 
			
		||||
    c11_vector__reserve(&alive, self->gen.count / 2);
 | 
			
		||||
@ -77,13 +77,13 @@ int pk_ManagedHeap__sweep(pk_ManagedHeap *self){
 | 
			
		||||
    return freed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PyObject* pk_ManagedHeap__new(pk_ManagedHeap *self, py_Type type, int slots, int udsize){
 | 
			
		||||
PyObject* ManagedHeap__new(ManagedHeap *self, py_Type type, int slots, int udsize){
 | 
			
		||||
    PyObject* obj = PyObject__new(type, slots, udsize);
 | 
			
		||||
    c11_vector__push(PyObject*, &self->no_gc, obj);
 | 
			
		||||
    return obj;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PyObject* pk_ManagedHeap__gcnew(pk_ManagedHeap *self, py_Type type, int slots, int udsize){
 | 
			
		||||
PyObject* ManagedHeap__gcnew(ManagedHeap *self, py_Type type, int slots, int udsize){
 | 
			
		||||
    PyObject* obj = PyObject__new(type, slots, udsize);
 | 
			
		||||
    c11_vector__push(PyObject*, &self->gen, obj);
 | 
			
		||||
    self->gc_counter++;
 | 
			
		||||
@ -111,7 +111,7 @@ PyObject* PyObject__new(py_Type type, int slots, int size){
 | 
			
		||||
    if(slots >= 0){
 | 
			
		||||
        memset(p, 0, slots*sizeof(py_TValue));
 | 
			
		||||
    }else{
 | 
			
		||||
        pk_NameDict__ctor(p);
 | 
			
		||||
        NameDict__ctor(p);
 | 
			
		||||
    }
 | 
			
		||||
    return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,131 +0,0 @@
 | 
			
		||||
#include "pocketpy/interpreter/vfs.h"
 | 
			
		||||
#include "pocketpy/interpreter/vm.h"
 | 
			
		||||
 | 
			
		||||
#define SMALLMAP_T__SOURCE
 | 
			
		||||
#define K c11_sv
 | 
			
		||||
#define V VfsEntry
 | 
			
		||||
#define NAME VfsDir
 | 
			
		||||
#define less(a, b) (c11_sv__cmp((a), (b)) < 0)
 | 
			
		||||
#define equal(a, b) (c11_sv__cmp((a), (b)) == 0)
 | 
			
		||||
#include "pocketpy/xmacros/smallmap.h"
 | 
			
		||||
#undef SMALLMAP_T__SOURCE
 | 
			
		||||
 | 
			
		||||
static VfsEntry* Vfs__get(const char* path) {
 | 
			
		||||
    c11_vector /*T=c11_sv*/ cpnts = c11_sv__split((c11_sv){path, strlen(path)}, '/');
 | 
			
		||||
 | 
			
		||||
    VfsEntry* root = &pk_current_vm->__vfs.root;
 | 
			
		||||
    for(int i = 0; i < cpnts.count; i++) {
 | 
			
		||||
        c11_sv cpnt = c11__getitem(c11_sv, &cpnts, i);
 | 
			
		||||
        VfsEntry* entry = VfsDir__try_get(&root->_dir, cpnt);
 | 
			
		||||
        if(entry == NULL) {
 | 
			
		||||
            c11_vector__dtor(&cpnts);
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
        if(entry->is_file) {
 | 
			
		||||
            VfsEntry* retval = i == cpnts.count - 1 ? entry : NULL;
 | 
			
		||||
            c11_vector__dtor(&cpnts);
 | 
			
		||||
            return retval;
 | 
			
		||||
        } else {
 | 
			
		||||
            root = entry;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    c11_vector__dtor(&cpnts);
 | 
			
		||||
    return root;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void VfsDir__delete_recursively(VfsDir* self) {
 | 
			
		||||
    for(int i = 0; i < self->count; i++) {
 | 
			
		||||
        VfsDir_KV* kv = c11__at(VfsDir_KV, self, i);
 | 
			
		||||
        free((char*)kv->key.data);
 | 
			
		||||
        if(kv->value.is_file) {
 | 
			
		||||
            free(kv->value._file.data);
 | 
			
		||||
        } else {
 | 
			
		||||
            VfsDir__delete_recursively(&kv->value._dir);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    VfsDir__dtor(self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Vfs__ctor(Vfs* self) {
 | 
			
		||||
    self->root.is_file = false;
 | 
			
		||||
    VfsDir__ctor(&self->root._dir);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Vfs__dtor(Vfs* self) { VfsDir__delete_recursively(&self->root._dir); }
 | 
			
		||||
 | 
			
		||||
unsigned char* py_vfsread(const char* path, int* size) {
 | 
			
		||||
    VfsEntry* entry = Vfs__get(path);
 | 
			
		||||
    if(entry == NULL || !entry->is_file) return NULL;
 | 
			
		||||
    *size = entry->_file.size;
 | 
			
		||||
    unsigned char* retval = malloc(*size);
 | 
			
		||||
    memcpy(retval, entry->_file.data, *size);
 | 
			
		||||
    return retval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void VfsDir__dupset(VfsDir* self, c11_sv key, VfsEntry value) {
 | 
			
		||||
    char* p = malloc(key.size);
 | 
			
		||||
    memcpy(p, key.data, key.size);
 | 
			
		||||
    VfsDir__set(self, (c11_sv){p, key.size}, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool py_vfswrite(const char* path, unsigned char* data, int size) {
 | 
			
		||||
    c11_vector /*T=c11_sv*/ cpnts = c11_sv__split((c11_sv){path, strlen(path)}, '/');
 | 
			
		||||
    VfsEntry* root = &pk_current_vm->__vfs.root;
 | 
			
		||||
    for(int i = 0; i < cpnts.count; i++) {
 | 
			
		||||
        c11_sv cpnt = c11__getitem(c11_sv, &cpnts, i);
 | 
			
		||||
        VfsEntry* entry = VfsDir__try_get(&root->_dir, cpnt);
 | 
			
		||||
        if(entry == NULL) {
 | 
			
		||||
            if(i == cpnts.count - 1) {
 | 
			
		||||
                // create file
 | 
			
		||||
                VfsEntry entry = {
 | 
			
		||||
                    .is_file = true,
 | 
			
		||||
                    ._file.size = size,
 | 
			
		||||
                    ._file.data = data,
 | 
			
		||||
                };
 | 
			
		||||
                VfsDir__dupset(&root->_dir, cpnt, entry);
 | 
			
		||||
                c11_vector__dtor(&cpnts);
 | 
			
		||||
                return true;
 | 
			
		||||
            } else {
 | 
			
		||||
                // create missing directory
 | 
			
		||||
                VfsEntry entry = {
 | 
			
		||||
                    .is_file = false,
 | 
			
		||||
                };
 | 
			
		||||
                VfsDir__ctor(&entry._dir);
 | 
			
		||||
                VfsDir__dupset(&root->_dir, cpnt, entry);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if(i == cpnts.count - 1) {
 | 
			
		||||
                if(!entry->is_file) break;
 | 
			
		||||
                // update file
 | 
			
		||||
                free(entry->_file.data);
 | 
			
		||||
                entry->_file.size = size;
 | 
			
		||||
                entry->_file.data = data;
 | 
			
		||||
                c11_vector__dtor(&cpnts);
 | 
			
		||||
                return true;
 | 
			
		||||
            } else {
 | 
			
		||||
                if(entry->is_file) break;
 | 
			
		||||
                root = entry;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    c11_vector__dtor(&cpnts);
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char** py_vfslist(const char* path, int* length) {
 | 
			
		||||
    VfsEntry* entry = Vfs__get(path);
 | 
			
		||||
    if(entry == NULL || entry->is_file) return NULL;
 | 
			
		||||
    *length = 0;
 | 
			
		||||
    char** ret = malloc(sizeof(char*) * entry->_dir.count);
 | 
			
		||||
    for(int i = 0; i < entry->_dir.count; i++) {
 | 
			
		||||
        VfsDir_KV* child = c11__at(VfsDir_KV, &entry->_dir, i);
 | 
			
		||||
        if(child->value.is_file) {
 | 
			
		||||
            int size = child->key.size;
 | 
			
		||||
            ret[i] = malloc(size + 1);
 | 
			
		||||
            memcpy(ret[i], child->key.data, size);
 | 
			
		||||
            ret[i][size] = '\0';
 | 
			
		||||
            (*length)++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
@ -6,23 +6,38 @@
 | 
			
		||||
#include "pocketpy/common/_generated.h"
 | 
			
		||||
#include "pocketpy/pocketpy.h"
 | 
			
		||||
 | 
			
		||||
static unsigned char* pk_default_import_file(const char* path, int* size) { return NULL; }
 | 
			
		||||
static char* pk_default_import_file(const char* path) {
 | 
			
		||||
#if PK_ENABLE_OS
 | 
			
		||||
    FILE* f = fopen(path, "rb");
 | 
			
		||||
    if(f == NULL) return NULL;
 | 
			
		||||
    fseek(f, 0, SEEK_END);
 | 
			
		||||
    long size = ftell(f);
 | 
			
		||||
    fseek(f, 0, SEEK_SET);
 | 
			
		||||
    char* buffer = malloc(size + 1);
 | 
			
		||||
    fread(buffer, 1, size, f);
 | 
			
		||||
    buffer[size] = 0;
 | 
			
		||||
    fclose(f);
 | 
			
		||||
    return buffer;
 | 
			
		||||
#else
 | 
			
		||||
    return NULL;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pk_default_print(const char* data) { printf("%s", data); }
 | 
			
		||||
 | 
			
		||||
static void pk_TypeInfo__ctor(pk_TypeInfo* self,
 | 
			
		||||
static void py_TypeInfo__ctor(py_TypeInfo* self,
 | 
			
		||||
                              py_Name name,
 | 
			
		||||
                              py_Type index,
 | 
			
		||||
                              py_Type base,
 | 
			
		||||
                              py_TValue module) {
 | 
			
		||||
    memset(self, 0, sizeof(pk_TypeInfo));
 | 
			
		||||
    memset(self, 0, sizeof(py_TypeInfo));
 | 
			
		||||
 | 
			
		||||
    self->name = name;
 | 
			
		||||
    self->base = base;
 | 
			
		||||
 | 
			
		||||
    // create type object with __dict__
 | 
			
		||||
    pk_ManagedHeap* heap = &pk_current_vm->heap;
 | 
			
		||||
    PyObject* typeobj = pk_ManagedHeap__new(heap, tp_type, -1, sizeof(py_Type));
 | 
			
		||||
    ManagedHeap* heap = &pk_current_vm->heap;
 | 
			
		||||
    PyObject* typeobj = ManagedHeap__new(heap, tp_type, -1, sizeof(py_Type));
 | 
			
		||||
    *(py_Type*)PyObject__userdata(typeobj) = index;
 | 
			
		||||
    self->self = (py_TValue){
 | 
			
		||||
        .type = typeobj->type,
 | 
			
		||||
@ -34,20 +49,13 @@ static void pk_TypeInfo__ctor(pk_TypeInfo* self,
 | 
			
		||||
    c11_vector__ctor(&self->annotated_fields, sizeof(py_Name));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pk_TypeInfo__dtor(pk_TypeInfo* self) { c11_vector__dtor(&self->annotated_fields); }
 | 
			
		||||
static void py_TypeInfo__dtor(py_TypeInfo* self) { c11_vector__dtor(&self->annotated_fields); }
 | 
			
		||||
 | 
			
		||||
static void save_site_package_to_vfs(const char* name, const char* source) {
 | 
			
		||||
    char buf[512];
 | 
			
		||||
    snprintf(buf, sizeof(buf), "site-packages/%s", name);
 | 
			
		||||
    bool ok = py_vfswrite(buf, (unsigned char*)source, strlen(source) + 1);
 | 
			
		||||
    if(!ok) c11__abort("failed to save '%s' to vfs", name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pk_VM__ctor(pk_VM* self) {
 | 
			
		||||
void VM__ctor(VM* self) {
 | 
			
		||||
    self->top_frame = NULL;
 | 
			
		||||
 | 
			
		||||
    pk_NameDict__ctor(&self->modules);
 | 
			
		||||
    c11_vector__ctor(&self->types, sizeof(pk_TypeInfo));
 | 
			
		||||
    NameDict__ctor(&self->modules);
 | 
			
		||||
    c11_vector__ctor(&self->types, sizeof(py_TypeInfo));
 | 
			
		||||
 | 
			
		||||
    self->builtins = *py_NIL;
 | 
			
		||||
    self->main = *py_NIL;
 | 
			
		||||
@ -60,17 +68,16 @@ void pk_VM__ctor(pk_VM* self) {
 | 
			
		||||
    self->curr_exception = *py_NIL;
 | 
			
		||||
    self->is_stopiteration = false;
 | 
			
		||||
 | 
			
		||||
    Vfs__ctor(&self->__vfs);
 | 
			
		||||
    self->__curr_class = NULL;
 | 
			
		||||
    self->__dynamic_func_decl = NULL;
 | 
			
		||||
 | 
			
		||||
    pk_ManagedHeap__ctor(&self->heap, self);
 | 
			
		||||
    ManagedHeap__ctor(&self->heap, self);
 | 
			
		||||
    ValueStack__ctor(&self->stack);
 | 
			
		||||
 | 
			
		||||
    /* Init Builtin Types */
 | 
			
		||||
    // 0: unused
 | 
			
		||||
    void* placeholder = c11_vector__emplace(&self->types);
 | 
			
		||||
    memset(placeholder, 0, sizeof(pk_TypeInfo));
 | 
			
		||||
    memset(placeholder, 0, sizeof(py_TypeInfo));
 | 
			
		||||
 | 
			
		||||
#define validate(t, expr)                                                                          \
 | 
			
		||||
    if(t != (expr)) abort()
 | 
			
		||||
@ -100,7 +107,7 @@ void pk_VM__ctor(pk_VM* self) {
 | 
			
		||||
    validate(tp_nativefunc, pk_nativefunc__register());
 | 
			
		||||
    validate(tp_boundmethod, pk_newtype("boundmethod", tp_object, NULL, NULL, false, true));
 | 
			
		||||
 | 
			
		||||
    validate(tp_super, pk_newtype("super", tp_object, NULL, NULL, false, true));
 | 
			
		||||
    validate(tp_super, pk_super__register());
 | 
			
		||||
    validate(tp_BaseException, pk_BaseException__register());
 | 
			
		||||
    validate(tp_Exception, pk_Exception__register());
 | 
			
		||||
    validate(tp_bytes, pk_bytes__register());
 | 
			
		||||
@ -109,11 +116,11 @@ void pk_VM__ctor(pk_VM* self) {
 | 
			
		||||
    validate(tp_dict, pk_dict__register());
 | 
			
		||||
    validate(tp_dict_items, pk_dict_items__register());
 | 
			
		||||
 | 
			
		||||
    validate(tp_property, pk_newtype("property", tp_object, NULL, NULL, false, true));
 | 
			
		||||
    validate(tp_property, pk_property__register());
 | 
			
		||||
    validate(tp_star_wrapper, pk_newtype("star_wrapper", tp_object, NULL, NULL, false, true));
 | 
			
		||||
 | 
			
		||||
    validate(tp_staticmethod, pk_newtype("staticmethod", tp_object, NULL, NULL, false, true));
 | 
			
		||||
    validate(tp_classmethod, pk_newtype("classmethod", tp_object, NULL, NULL, false, true));
 | 
			
		||||
    validate(tp_staticmethod, pk_staticmethod__register());
 | 
			
		||||
    validate(tp_classmethod, pk_classmethod__register());
 | 
			
		||||
 | 
			
		||||
    validate(tp_NoneType, pk_newtype("NoneType", tp_object, NULL, NULL, false, true));
 | 
			
		||||
    validate(tp_NotImplementedType,
 | 
			
		||||
@ -127,27 +134,15 @@ void pk_VM__ctor(pk_VM* self) {
 | 
			
		||||
    self->builtins = pk_builtins__register();
 | 
			
		||||
 | 
			
		||||
    /* Setup Public Builtin Types */
 | 
			
		||||
    py_Type public_types[] = {tp_object,
 | 
			
		||||
                              tp_type,
 | 
			
		||||
                              tp_int,
 | 
			
		||||
                              tp_float,
 | 
			
		||||
                              tp_bool,
 | 
			
		||||
                              tp_str,
 | 
			
		||||
                              tp_list,
 | 
			
		||||
                              tp_tuple,
 | 
			
		||||
                              tp_slice,
 | 
			
		||||
                              tp_range,
 | 
			
		||||
                              tp_bytes,
 | 
			
		||||
                              tp_dict,
 | 
			
		||||
                              tp_property,
 | 
			
		||||
                              tp_BaseException,
 | 
			
		||||
                              tp_Exception,
 | 
			
		||||
                              tp_StopIteration,
 | 
			
		||||
                              tp_SyntaxError};
 | 
			
		||||
    py_Type public_types[] = {tp_object,        tp_type,         tp_int,           tp_float,
 | 
			
		||||
                              tp_bool,          tp_str,          tp_list,          tp_tuple,
 | 
			
		||||
                              tp_slice,         tp_range,        tp_bytes,         tp_dict,
 | 
			
		||||
                              tp_property,      tp_staticmethod, tp_classmethod,   tp_super,
 | 
			
		||||
                              tp_BaseException, tp_Exception,    tp_StopIteration, tp_SyntaxError};
 | 
			
		||||
 | 
			
		||||
    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_TypeInfo* ti = c11__at(py_TypeInfo, &self->types, t);
 | 
			
		||||
        py_setdict(&self->builtins, ti->name, py_tpobject(t));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -155,6 +150,7 @@ void pk_VM__ctor(pk_VM* self) {
 | 
			
		||||
    const char** builtin_exceptions = (const char*[]){
 | 
			
		||||
        "StackOverflowError",
 | 
			
		||||
        "IOError",
 | 
			
		||||
        "OSError",
 | 
			
		||||
        "NotImplementedError",
 | 
			
		||||
        "TypeError",
 | 
			
		||||
        "IndexError",
 | 
			
		||||
@ -182,45 +178,35 @@ void pk_VM__ctor(pk_VM* self) {
 | 
			
		||||
 | 
			
		||||
    // add modules
 | 
			
		||||
    pk__add_module_pkpy();
 | 
			
		||||
    pk__add_module_os();
 | 
			
		||||
    pk__add_module_math();
 | 
			
		||||
 | 
			
		||||
    self->main = *py_newmodule("__main__");
 | 
			
		||||
 | 
			
		||||
    save_site_package_to_vfs("bisect.py", kPythonLibs_bisect);
 | 
			
		||||
    save_site_package_to_vfs("cmath.py", kPythonLibs_cmath);
 | 
			
		||||
    save_site_package_to_vfs("collections.py", kPythonLibs_collections);
 | 
			
		||||
    save_site_package_to_vfs("colorsys.py", kPythonLibs_colorsys);
 | 
			
		||||
    save_site_package_to_vfs("datetime.py", kPythonLibs_datetime);
 | 
			
		||||
    save_site_package_to_vfs("functools.py", kPythonLibs_functools);
 | 
			
		||||
    save_site_package_to_vfs("heapq.py", kPythonLibs_heapq);
 | 
			
		||||
    save_site_package_to_vfs("itertools.py", kPythonLibs_itertools);
 | 
			
		||||
    save_site_package_to_vfs("operator.py", kPythonLibs_operator);
 | 
			
		||||
    save_site_package_to_vfs("pickle.py", kPythonLibs_pickle);
 | 
			
		||||
    save_site_package_to_vfs("this.py", kPythonLibs_this);
 | 
			
		||||
    save_site_package_to_vfs("typing.py", kPythonLibs_typing);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pk_VM__dtor(pk_VM* self) {
 | 
			
		||||
void VM__dtor(VM* self) {
 | 
			
		||||
    if(self->__dynamic_func_decl) { PK_DECREF(self->__dynamic_func_decl); }
 | 
			
		||||
    // destroy all objects
 | 
			
		||||
    pk_ManagedHeap__dtor(&self->heap);
 | 
			
		||||
    ManagedHeap__dtor(&self->heap);
 | 
			
		||||
    // clear frames
 | 
			
		||||
    // ...
 | 
			
		||||
    pk_NameDict__dtor(&self->modules);
 | 
			
		||||
    c11__foreach(pk_TypeInfo, &self->types, ti) pk_TypeInfo__dtor(ti);
 | 
			
		||||
    while(self->top_frame)
 | 
			
		||||
        VM__pop_frame(self);
 | 
			
		||||
    NameDict__dtor(&self->modules);
 | 
			
		||||
    c11__foreach(py_TypeInfo, &self->types, ti) py_TypeInfo__dtor(ti);
 | 
			
		||||
    c11_vector__dtor(&self->types);
 | 
			
		||||
    ValueStack__clear(&self->stack);
 | 
			
		||||
    Vfs__dtor(&self->__vfs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pk_VM__push_frame(pk_VM* self, Frame* frame) {
 | 
			
		||||
void VM__push_frame(VM* self, Frame* frame) {
 | 
			
		||||
    frame->f_back = self->top_frame;
 | 
			
		||||
    self->top_frame = frame;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pk_VM__pop_frame(pk_VM* self) {
 | 
			
		||||
void VM__pop_frame(VM* self) {
 | 
			
		||||
    assert(self->top_frame);
 | 
			
		||||
    Frame* frame = self->top_frame;
 | 
			
		||||
    // reset stack pointer
 | 
			
		||||
 | 
			
		||||
    self->stack.sp = frame->p0;
 | 
			
		||||
    // pop frame and delete
 | 
			
		||||
    self->top_frame = frame->f_back;
 | 
			
		||||
@ -297,9 +283,9 @@ py_Type pk_newtype(const char* name,
 | 
			
		||||
                   bool is_sealed) {
 | 
			
		||||
    c11_vector* types = &pk_current_vm->types;
 | 
			
		||||
    py_Type index = types->count;
 | 
			
		||||
    pk_TypeInfo* ti = c11_vector__emplace(types);
 | 
			
		||||
    pk_TypeInfo__ctor(ti, py_name(name), index, base, module ? *module : *py_NIL);
 | 
			
		||||
    if(!dtor && base) { dtor = c11__at(pk_TypeInfo, types, base)->dtor; }
 | 
			
		||||
    py_TypeInfo* ti = c11_vector__emplace(types);
 | 
			
		||||
    py_TypeInfo__ctor(ti, py_name(name), index, base, module ? *module : *py_NIL);
 | 
			
		||||
    if(!dtor && base) { dtor = c11__at(py_TypeInfo, types, base)->dtor; }
 | 
			
		||||
    ti->dtor = dtor;
 | 
			
		||||
    ti->is_python = is_python;
 | 
			
		||||
    ti->is_sealed = is_sealed;
 | 
			
		||||
@ -377,7 +363,7 @@ static bool
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bool opcall) {
 | 
			
		||||
FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall) {
 | 
			
		||||
    pk_print_stack(self, self->top_frame, (Bytecode){0});
 | 
			
		||||
 | 
			
		||||
    py_Ref p1 = self->stack.sp - kwargc * 2;
 | 
			
		||||
@ -385,18 +371,14 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo
 | 
			
		||||
    // [callable, <self>, args..., kwargs...]
 | 
			
		||||
    //      ^p0                    ^p1      ^_sp
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
    // handle boundmethod, do a patch
 | 
			
		||||
    if(p0->type == tp_boundmethod) {
 | 
			
		||||
        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);
 | 
			
		||||
        // p1[-(ARGC + 2)] = bm.func;
 | 
			
		||||
        // p1[-(ARGC + 1)] = bm.self;
 | 
			
		||||
        py_TValue* slots = PyObject__slots(p0->_obj);
 | 
			
		||||
        p0[0] = slots[1];  // callable
 | 
			
		||||
        p0[1] = slots[0];  // self
 | 
			
		||||
        // [unbound, self, args..., kwargs...]
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    py_Ref argv = py_isnil(p0 + 1) ? p0 + 2 : p0 + 1;
 | 
			
		||||
 | 
			
		||||
@ -420,8 +402,8 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo
 | 
			
		||||
                memcpy(argv, self->__vectorcall_buffer, co->nlocals * sizeof(py_TValue));
 | 
			
		||||
                // submit the call
 | 
			
		||||
                if(!fn->cfunc) {
 | 
			
		||||
                    pk_VM__push_frame(self, Frame__new(co, &fn->module, p0, p0, argv, co));
 | 
			
		||||
                    return opcall ? RES_CALL : pk_VM__run_top_frame(self);
 | 
			
		||||
                    VM__push_frame(self, Frame__new(co, &fn->module, p0, p0, argv, co));
 | 
			
		||||
                    return opcall ? RES_CALL : VM__run_top_frame(self);
 | 
			
		||||
                } else {
 | 
			
		||||
                    bool ok = fn->cfunc(co->nlocals, argv);
 | 
			
		||||
                    self->stack.sp = p0;
 | 
			
		||||
@ -444,8 +426,8 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo
 | 
			
		||||
                // initialize local variables to py_NIL
 | 
			
		||||
                memset(p1, 0, (char*)self->stack.sp - (char*)p1);
 | 
			
		||||
                // submit the call
 | 
			
		||||
                pk_VM__push_frame(self, Frame__new(co, &fn->module, p0, p0, argv, co));
 | 
			
		||||
                return opcall ? RES_CALL : pk_VM__run_top_frame(self);
 | 
			
		||||
                VM__push_frame(self, Frame__new(co, &fn->module, p0, p0, argv, co));
 | 
			
		||||
                return opcall ? RES_CALL : VM__run_top_frame(self);
 | 
			
		||||
            case FuncType_GENERATOR:
 | 
			
		||||
                assert(false);
 | 
			
		||||
                break;
 | 
			
		||||
@ -480,7 +462,7 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo
 | 
			
		||||
        memcpy(self->stack.sp, argv, span * sizeof(py_TValue));
 | 
			
		||||
        self->stack.sp += span;
 | 
			
		||||
        // [new_f, cls, args..., kwargs...]
 | 
			
		||||
        if(pk_VM__vectorcall(self, argc, kwargc, false) == RES_ERROR) return RES_ERROR;
 | 
			
		||||
        if(VM__vectorcall(self, argc, kwargc, false) == RES_ERROR) return RES_ERROR;
 | 
			
		||||
        // by recursively using vectorcall, args and kwargs are consumed
 | 
			
		||||
 | 
			
		||||
        // try __init__
 | 
			
		||||
@ -493,7 +475,7 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo
 | 
			
		||||
            *p0 = *init_f;              // __init__
 | 
			
		||||
            p0[1] = self->last_retval;  // self
 | 
			
		||||
            // [__init__, self, args..., kwargs...]
 | 
			
		||||
            if(pk_VM__vectorcall(self, argc, kwargc, false) == RES_ERROR) return RES_ERROR;
 | 
			
		||||
            if(VM__vectorcall(self, argc, kwargc, false) == RES_ERROR) return RES_ERROR;
 | 
			
		||||
            *py_retval() = p0[1];  // restore the new instance
 | 
			
		||||
        }
 | 
			
		||||
        // reset the stack
 | 
			
		||||
@ -504,18 +486,18 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo
 | 
			
		||||
    // handle `__call__` overload
 | 
			
		||||
    if(pk_pushmethod(p0, __call__)) {
 | 
			
		||||
        // [__call__, self, args..., kwargs...]
 | 
			
		||||
        return pk_VM__vectorcall(self, argc, kwargc, opcall);
 | 
			
		||||
        return VM__vectorcall(self, argc, kwargc, opcall);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    TypeError("'%t' object is not callable", p0->type);
 | 
			
		||||
    c11__unreachedable();
 | 
			
		||||
    return RES_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/****************************************/
 | 
			
		||||
void PyObject__delete(PyObject* self) {
 | 
			
		||||
    pk_TypeInfo* ti = c11__at(pk_TypeInfo, &pk_current_vm->types, self->type);
 | 
			
		||||
    py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, self->type);
 | 
			
		||||
    if(ti->dtor) ti->dtor(PyObject__userdata(self));
 | 
			
		||||
    if(self->slots == -1) pk_NameDict__dtor(PyObject__dict(self));
 | 
			
		||||
    if(self->slots == -1) NameDict__dtor(PyObject__dict(self));
 | 
			
		||||
    if(self->gc_is_large) {
 | 
			
		||||
        free(self);
 | 
			
		||||
    } else {
 | 
			
		||||
@ -541,9 +523,9 @@ static void mark_object(PyObject* obj) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(obj->slots == -1) {
 | 
			
		||||
        pk_NameDict* dict = PyObject__dict(obj);
 | 
			
		||||
        NameDict* dict = PyObject__dict(obj);
 | 
			
		||||
        for(int j = 0; j < dict->count; j++) {
 | 
			
		||||
            pk_NameDict_KV* kv = c11__at(pk_NameDict_KV, dict, j);
 | 
			
		||||
            NameDict_KV* kv = c11__at(NameDict_KV, dict, j);
 | 
			
		||||
            mark_value(&kv->value);
 | 
			
		||||
        }
 | 
			
		||||
        return;
 | 
			
		||||
@ -556,8 +538,8 @@ static void mark_object(PyObject* obj) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pk_ManagedHeap__mark(pk_ManagedHeap* self) {
 | 
			
		||||
    pk_VM* vm = self->vm;
 | 
			
		||||
void ManagedHeap__mark(ManagedHeap* self) {
 | 
			
		||||
    VM* vm = self->vm;
 | 
			
		||||
    // mark heap objects
 | 
			
		||||
    for(int i = 0; i < self->no_gc.count; i++) {
 | 
			
		||||
        PyObject* obj = c11__getitem(PyObject*, &self->no_gc, i);
 | 
			
		||||
@ -580,8 +562,8 @@ void pk_ManagedHeap__mark(pk_ManagedHeap* self) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pk_print_stack(pk_VM* self, Frame* frame, Bytecode byte) {
 | 
			
		||||
    // return;
 | 
			
		||||
void pk_print_stack(VM* self, Frame* frame, Bytecode byte) {
 | 
			
		||||
    return;
 | 
			
		||||
    if(frame == NULL) return;
 | 
			
		||||
 | 
			
		||||
    py_TValue* sp = self->stack.sp;
 | 
			
		||||
@ -616,6 +598,11 @@ void pk_print_stack(pk_VM* self, Frame* frame, Bytecode byte) {
 | 
			
		||||
                pk_sprintf(&buf, "%q", py_tosv(p));
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            case tp_module: {
 | 
			
		||||
                py_Ref path = py_getdict(p, __path__);
 | 
			
		||||
                pk_sprintf(&buf, "<module '%v'>", py_tosv(path));
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            default: {
 | 
			
		||||
                pk_sprintf(&buf, "(%t)", p->type);
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										202
									
								
								src/modules/math.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								src/modules/math.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,202 @@
 | 
			
		||||
#include "pocketpy/pocketpy.h"
 | 
			
		||||
 | 
			
		||||
#include "pocketpy/common/utils.h"
 | 
			
		||||
#include "pocketpy/objects/object.h"
 | 
			
		||||
#include "pocketpy/common/sstream.h"
 | 
			
		||||
#include "pocketpy/interpreter/vm.h"
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
#define ONE_ARG_FUNC(name, func)                                                                   \
 | 
			
		||||
    static bool math_##name(int argc, py_Ref argv) {                                               \
 | 
			
		||||
        PY_CHECK_ARGC(1);                                                                          \
 | 
			
		||||
        double x;                                                                                  \
 | 
			
		||||
        if(!py_castfloat(py_arg(0), &x)) return false;                                             \
 | 
			
		||||
        py_newfloat(py_retval(), func(x));                                                         \
 | 
			
		||||
        return true;                                                                               \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#define TWO_ARG_FUNC(name, func)                                                                   \
 | 
			
		||||
    static bool math_##name(int argc, py_Ref argv) {                                               \
 | 
			
		||||
        PY_CHECK_ARGC(2);                                                                          \
 | 
			
		||||
        double x, y;                                                                               \
 | 
			
		||||
        if(!py_castfloat(py_arg(0), &x)) return false;                                             \
 | 
			
		||||
        if(!py_castfloat(py_arg(1), &y)) return false;                                             \
 | 
			
		||||
        py_newfloat(py_retval(), func(x, y));                                                      \
 | 
			
		||||
        return true;                                                                               \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
ONE_ARG_FUNC(ceil, ceil)
 | 
			
		||||
ONE_ARG_FUNC(fabs, fabs)
 | 
			
		||||
ONE_ARG_FUNC(floor, floor)
 | 
			
		||||
ONE_ARG_FUNC(trunc, trunc)
 | 
			
		||||
 | 
			
		||||
static bool math_fsum(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    PY_CHECK_ARG_TYPE(0, tp_list);
 | 
			
		||||
    py_Ref list = py_arg(0);
 | 
			
		||||
    double sum = 0;
 | 
			
		||||
    double c = 0;
 | 
			
		||||
    for(int i = 0; i < py_list__len(list); i++) {
 | 
			
		||||
        py_Ref item = py_list__getitem(list, i);
 | 
			
		||||
        double x;
 | 
			
		||||
        if(!py_castfloat(item, &x)) return false;
 | 
			
		||||
        double y = x - c;
 | 
			
		||||
        double t = sum + y;
 | 
			
		||||
        c = (t - sum) - y;
 | 
			
		||||
        sum = t;
 | 
			
		||||
    }
 | 
			
		||||
    py_newfloat(py_retval(), sum);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool math_gcd(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    PY_CHECK_ARG_TYPE(0, tp_int);
 | 
			
		||||
    PY_CHECK_ARG_TYPE(1, tp_int);
 | 
			
		||||
    py_i64 a = py_toint(py_arg(0));
 | 
			
		||||
    py_i64 b = py_toint(py_arg(1));
 | 
			
		||||
    if(a < 0) a = -a;
 | 
			
		||||
    if(b < 0) b = -b;
 | 
			
		||||
    while(b != 0) {
 | 
			
		||||
        py_i64 t = b;
 | 
			
		||||
        b = a % b;
 | 
			
		||||
        a = t;
 | 
			
		||||
    }
 | 
			
		||||
    py_newint(py_retval(), a);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ONE_ARG_FUNC(isfinite, isfinite)
 | 
			
		||||
ONE_ARG_FUNC(isinf, isinf)
 | 
			
		||||
ONE_ARG_FUNC(isnan, isnan)
 | 
			
		||||
 | 
			
		||||
static bool math_isclose(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    double a, b;
 | 
			
		||||
    if(!py_castfloat(py_arg(0), &a)) return false;
 | 
			
		||||
    if(!py_castfloat(py_arg(1), &b)) return false;
 | 
			
		||||
    py_newbool(py_retval(), fabs(a - b) < 1e-9);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ONE_ARG_FUNC(exp, exp)
 | 
			
		||||
 | 
			
		||||
static bool math_log(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARG_TYPE(0, tp_float);
 | 
			
		||||
    double x;
 | 
			
		||||
    if(!py_castfloat(py_arg(0), &x)) return false;
 | 
			
		||||
    if(argc == 1) {
 | 
			
		||||
        py_newfloat(py_retval(), log(x));
 | 
			
		||||
    } else if(argc == 2) {
 | 
			
		||||
        double base;
 | 
			
		||||
        if(!py_castfloat(py_arg(1), &base)) return false;
 | 
			
		||||
        py_newfloat(py_retval(), log(x) / log(base));
 | 
			
		||||
    } else {
 | 
			
		||||
        return TypeError("log() takes 1 or 2 arguments");
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ONE_ARG_FUNC(log2, log2)
 | 
			
		||||
ONE_ARG_FUNC(log10, log10)
 | 
			
		||||
 | 
			
		||||
TWO_ARG_FUNC(pow, pow)
 | 
			
		||||
 | 
			
		||||
ONE_ARG_FUNC(sqrt, sqrt)
 | 
			
		||||
 | 
			
		||||
ONE_ARG_FUNC(acos, acos)
 | 
			
		||||
ONE_ARG_FUNC(asin, asin)
 | 
			
		||||
ONE_ARG_FUNC(atan, atan)
 | 
			
		||||
 | 
			
		||||
ONE_ARG_FUNC(cos, cos)
 | 
			
		||||
ONE_ARG_FUNC(sin, sin)
 | 
			
		||||
ONE_ARG_FUNC(tan, tan)
 | 
			
		||||
 | 
			
		||||
TWO_ARG_FUNC(atan2, atan2)
 | 
			
		||||
 | 
			
		||||
static bool math_degrees(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    double x;
 | 
			
		||||
    if(!py_castfloat(py_arg(0), &x)) return false;
 | 
			
		||||
    py_newfloat(py_retval(), x * 180 / 3.1415926535897932384);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool math_radians(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    double x;
 | 
			
		||||
    if(!py_castfloat(py_arg(0), &x)) return false;
 | 
			
		||||
    py_newfloat(py_retval(), x * 3.1415926535897932384 / 180);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool math_modf(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    double i;
 | 
			
		||||
    double f = modf(py_tofloat(py_arg(0)), &i);
 | 
			
		||||
    py_newtuple(py_retval(), 2);
 | 
			
		||||
    py_Ref _0 = py_tuple__getitem(py_retval(), 0);
 | 
			
		||||
    py_Ref _1 = py_tuple__getitem(py_retval(), 1);
 | 
			
		||||
    py_newfloat(_0, f);
 | 
			
		||||
    py_newfloat(_1, i);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool math_factorial(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    PY_CHECK_ARG_TYPE(0, tp_int);
 | 
			
		||||
    py_i64 n = py_toint(py_arg(0));
 | 
			
		||||
    if(n < 0) return ValueError("factorial() not defined for negative values");
 | 
			
		||||
    py_i64 r = 1;
 | 
			
		||||
    for(py_i64 i = 2; i <= n; i++)
 | 
			
		||||
        r *= i;
 | 
			
		||||
    py_newint(py_retval(), r);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pk__add_module_math() {
 | 
			
		||||
    py_Ref mod = py_newmodule("math");
 | 
			
		||||
 | 
			
		||||
    py_newfloat(py_emplacedict(mod, py_name("pi")), 3.1415926535897932384);
 | 
			
		||||
    py_newfloat(py_emplacedict(mod, py_name("e")), 2.7182818284590452354);
 | 
			
		||||
    py_newfloat(py_emplacedict(mod, py_name("inf")), 1.0 / 0.0);
 | 
			
		||||
    py_newfloat(py_emplacedict(mod, py_name("nan")), 0.0 / 0.0);
 | 
			
		||||
 | 
			
		||||
    py_bindfunc(mod, "ceil", math_ceil);
 | 
			
		||||
    py_bindfunc(mod, "fabs", math_fabs);
 | 
			
		||||
    py_bindfunc(mod, "floor", math_floor);
 | 
			
		||||
    py_bindfunc(mod, "trunc", math_trunc);
 | 
			
		||||
 | 
			
		||||
    py_bindfunc(mod, "fsum", math_fsum);
 | 
			
		||||
    py_bindfunc(mod, "gcd", math_gcd);
 | 
			
		||||
 | 
			
		||||
    py_bindfunc(mod, "isfinite", math_isfinite);
 | 
			
		||||
    py_bindfunc(mod, "isinf", math_isinf);
 | 
			
		||||
    py_bindfunc(mod, "isnan", math_isnan);
 | 
			
		||||
    py_bindfunc(mod, "isclose", math_isclose);
 | 
			
		||||
 | 
			
		||||
    py_bindfunc(mod, "exp", math_exp);
 | 
			
		||||
    py_bindfunc(mod, "log", math_log);
 | 
			
		||||
    py_bindfunc(mod, "log2", math_log2);
 | 
			
		||||
    py_bindfunc(mod, "log10", math_log10);
 | 
			
		||||
 | 
			
		||||
    py_bindfunc(mod, "pow", math_pow);
 | 
			
		||||
    py_bindfunc(mod, "sqrt", math_sqrt);
 | 
			
		||||
 | 
			
		||||
    py_bindfunc(mod, "acos", math_acos);
 | 
			
		||||
    py_bindfunc(mod, "asin", math_asin);
 | 
			
		||||
    py_bindfunc(mod, "atan", math_atan);
 | 
			
		||||
 | 
			
		||||
    py_bindfunc(mod, "cos", math_cos);
 | 
			
		||||
    py_bindfunc(mod, "sin", math_sin);
 | 
			
		||||
    py_bindfunc(mod, "tan", math_tan);
 | 
			
		||||
 | 
			
		||||
    py_bindfunc(mod, "atan2", math_atan2);
 | 
			
		||||
 | 
			
		||||
    py_bindfunc(mod, "degrees", math_degrees);
 | 
			
		||||
    py_bindfunc(mod, "radians", math_radians);
 | 
			
		||||
 | 
			
		||||
    py_bindfunc(mod, "modf", math_modf);
 | 
			
		||||
    py_bindfunc(mod, "factorial", math_factorial);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								src/modules/os.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/modules/os.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,49 @@
 | 
			
		||||
#include "pocketpy/pocketpy.h"
 | 
			
		||||
 | 
			
		||||
#include "pocketpy/common/utils.h"
 | 
			
		||||
#include "pocketpy/objects/object.h"
 | 
			
		||||
#include "pocketpy/common/sstream.h"
 | 
			
		||||
#include "pocketpy/interpreter/vm.h"
 | 
			
		||||
 | 
			
		||||
#if _WIN32
 | 
			
		||||
#include <direct.h>
 | 
			
		||||
 | 
			
		||||
int platform_chdir(const char* path) { return _chdir(path); }
 | 
			
		||||
 | 
			
		||||
bool platform_getcwd(char* buf, size_t size) { return _getcwd(buf, size) != NULL; }
 | 
			
		||||
 | 
			
		||||
#elif __linux__
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
int platform_chdir(const char* path) { return chdir(path); }
 | 
			
		||||
 | 
			
		||||
bool platform_getcwd(char* buf, size_t size) { return getcwd(buf, size) != NULL; }
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
int platform_chdir(const char* path) { return -1; }
 | 
			
		||||
 | 
			
		||||
bool platform_getcwd(char* buf, size_t size) { return false; }
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static bool os_chdir(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    PY_CHECK_ARG_TYPE(0, tp_str);
 | 
			
		||||
    const char* path = py_tostr(py_arg(0));
 | 
			
		||||
    int code = platform_chdir(path);
 | 
			
		||||
    if(code != 0) return OSError("chdir() failed: %d", code);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool os_getcwd(int argc, py_Ref argv) {
 | 
			
		||||
    char buf[1024];
 | 
			
		||||
    if(!platform_getcwd(buf, sizeof(buf))) return OSError("getcwd() failed");
 | 
			
		||||
    py_newstr(py_retval(), buf);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pk__add_module_os() {
 | 
			
		||||
    py_Ref mod = py_newmodule("os");
 | 
			
		||||
    py_bindfunc(mod, "chdir", os_chdir);
 | 
			
		||||
    py_bindfunc(mod, "getcwd", os_getcwd);
 | 
			
		||||
}
 | 
			
		||||
@ -20,7 +20,7 @@ static void FuncDecl__dtor(FuncDecl* self) {
 | 
			
		||||
    c11_smallmap_n2i__dtor(&self->kw_to_index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FuncDecl_ FuncDecl__rcnew(pk_SourceData_ src, c11_sv name) {
 | 
			
		||||
FuncDecl_ FuncDecl__rcnew(SourceData_ src, c11_sv name) {
 | 
			
		||||
    FuncDecl* self = malloc(sizeof(FuncDecl));
 | 
			
		||||
    self->rc.count = 1;
 | 
			
		||||
    self->rc.dtor = (void (*)(void*))FuncDecl__dtor;
 | 
			
		||||
@ -94,7 +94,7 @@ FuncDecl_ FuncDecl__build(c11_sv name,
 | 
			
		||||
                          py_Ref kwdefaults,  // a tuple contains default values
 | 
			
		||||
                          c11_sv starred_kwarg,
 | 
			
		||||
                          const char* docstring) {
 | 
			
		||||
    pk_SourceData_ source = pk_SourceData__rcnew("pass", "<bind>", EXEC_MODE, false);
 | 
			
		||||
    SourceData_ source = SourceData__rcnew("pass", "<bind>", EXEC_MODE, false);
 | 
			
		||||
    FuncDecl_ decl = FuncDecl__rcnew(source, name);
 | 
			
		||||
    for(int i = 0; i < argc; i++) {
 | 
			
		||||
        FuncDecl__add_arg(decl, py_namev(args[i]));
 | 
			
		||||
@ -111,7 +111,7 @@ FuncDecl_ FuncDecl__build(c11_sv name,
 | 
			
		||||
    return decl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CodeObject__ctor(CodeObject* self, pk_SourceData_ src, c11_sv name) {
 | 
			
		||||
void CodeObject__ctor(CodeObject* self, SourceData_ src, c11_sv name) {
 | 
			
		||||
    self->src = src;
 | 
			
		||||
    PK_INCREF(src);
 | 
			
		||||
    self->name = c11_string__new2(name.data, name.size);
 | 
			
		||||
@ -179,5 +179,5 @@ int CodeObject__add_varname(CodeObject* self, py_Name name) {
 | 
			
		||||
 | 
			
		||||
void Function__dtor(Function* self) {
 | 
			
		||||
    PK_DECREF(self->decl);
 | 
			
		||||
    if(self->closure) pk_NameDict__delete(self->closure);
 | 
			
		||||
    if(self->closure) NameDict__delete(self->closure);
 | 
			
		||||
}
 | 
			
		||||
@ -3,6 +3,6 @@
 | 
			
		||||
#define SMALLMAP_T__SOURCE
 | 
			
		||||
#define K uint16_t
 | 
			
		||||
#define V py_TValue
 | 
			
		||||
#define NAME pk_NameDict
 | 
			
		||||
#define NAME NameDict
 | 
			
		||||
#include "pocketpy/xmacros/smallmap.h"
 | 
			
		||||
#undef SMALLMAP_T__SOURCE
 | 
			
		||||
 | 
			
		||||
@ -4,9 +4,9 @@
 | 
			
		||||
 | 
			
		||||
void* PyObject__userdata(PyObject* self) { return self->flex + PK_OBJ_SLOTS_SIZE(self->slots); }
 | 
			
		||||
 | 
			
		||||
pk_NameDict* PyObject__dict(PyObject* self) {
 | 
			
		||||
NameDict* PyObject__dict(PyObject* self) {
 | 
			
		||||
    assert(self->slots == -1);
 | 
			
		||||
    return (pk_NameDict*)(self->flex);
 | 
			
		||||
    return (NameDict*)(self->flex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
py_TValue* PyObject__slots(PyObject* self) {
 | 
			
		||||
 | 
			
		||||
@ -19,7 +19,7 @@ bool py_castfloat(py_Ref self, double* out) {
 | 
			
		||||
    switch(self->type) {
 | 
			
		||||
        case tp_int: *out = (double)self->_i64; return true;
 | 
			
		||||
        case tp_float: *out = self->_f64; return true;
 | 
			
		||||
        default: return false;
 | 
			
		||||
        default: return TypeError("expected int or float, got %t", self->type);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -46,12 +46,10 @@ bool py_checktype(py_Ref self, py_Type type) {
 | 
			
		||||
    return TypeError("expected %t, got %t", type, self->type);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool py_isinstance(py_Ref obj, py_Type type){
 | 
			
		||||
    return py_issubclass(obj->type, type);
 | 
			
		||||
}
 | 
			
		||||
bool py_isinstance(py_Ref obj, py_Type type) { return py_issubclass(obj->type, type); }
 | 
			
		||||
 | 
			
		||||
bool py_issubclass(py_Type derived, py_Type base){
 | 
			
		||||
    pk_TypeInfo* types = pk_current_vm->types.data;
 | 
			
		||||
bool py_issubclass(py_Type derived, py_Type base) {
 | 
			
		||||
    py_TypeInfo* types = pk_current_vm->types.data;
 | 
			
		||||
    do {
 | 
			
		||||
        if(derived == base) return true;
 | 
			
		||||
        derived = types[derived].base;
 | 
			
		||||
 | 
			
		||||
@ -9,18 +9,18 @@
 | 
			
		||||
#include "pocketpy/compiler/compiler.h"
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
pk_VM* pk_current_vm;
 | 
			
		||||
VM* pk_current_vm;
 | 
			
		||||
 | 
			
		||||
py_GlobalRef py_True;
 | 
			
		||||
py_GlobalRef py_False;
 | 
			
		||||
py_GlobalRef py_None;
 | 
			
		||||
py_GlobalRef py_NIL;
 | 
			
		||||
 | 
			
		||||
static pk_VM pk_default_vm;
 | 
			
		||||
static pk_VM* pk_all_vm[16];
 | 
			
		||||
static VM pk_default_vm;
 | 
			
		||||
static VM* pk_all_vm[16];
 | 
			
		||||
 | 
			
		||||
void py_initialize() {
 | 
			
		||||
    pk_MemoryPools__initialize();
 | 
			
		||||
    MemoryPools__initialize();
 | 
			
		||||
    py_Name__initialize();
 | 
			
		||||
 | 
			
		||||
    pk_current_vm = pk_all_vm[0] = &pk_default_vm;
 | 
			
		||||
@ -35,28 +35,28 @@ void py_initialize() {
 | 
			
		||||
    py_False = &_False;
 | 
			
		||||
    py_None = &_None;
 | 
			
		||||
    py_NIL = &_NIL;
 | 
			
		||||
    pk_VM__ctor(&pk_default_vm);
 | 
			
		||||
    VM__ctor(&pk_default_vm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void py_finalize() {
 | 
			
		||||
    for(int i = 1; i < 16; i++) {
 | 
			
		||||
        pk_VM* vm = pk_all_vm[i];
 | 
			
		||||
        VM* vm = pk_all_vm[i];
 | 
			
		||||
        if(vm) {
 | 
			
		||||
            pk_VM__dtor(vm);
 | 
			
		||||
            VM__dtor(vm);
 | 
			
		||||
            free(vm);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pk_VM__dtor(&pk_default_vm);
 | 
			
		||||
    VM__dtor(&pk_default_vm);
 | 
			
		||||
    pk_current_vm = NULL;
 | 
			
		||||
    py_Name__finalize();
 | 
			
		||||
    pk_MemoryPools__finalize();
 | 
			
		||||
    MemoryPools__finalize();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void py_switchvm(int index) {
 | 
			
		||||
    if(index < 0 || index >= 16) c11__abort("invalid vm index");
 | 
			
		||||
    if(!pk_all_vm[index]) {
 | 
			
		||||
        pk_all_vm[index] = malloc(sizeof(pk_VM));
 | 
			
		||||
        pk_VM__ctor(pk_all_vm[index]);
 | 
			
		||||
        pk_all_vm[index] = malloc(sizeof(VM));
 | 
			
		||||
        VM__ctor(pk_all_vm[index]);
 | 
			
		||||
    }
 | 
			
		||||
    pk_current_vm = pk_all_vm[index];
 | 
			
		||||
}
 | 
			
		||||
@ -184,9 +184,9 @@ static void disassemble(CodeObject* co) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool py_exec(const char* source, const char* filename, enum py_CompileMode mode, py_Ref module) {
 | 
			
		||||
    pk_VM* vm = pk_current_vm;
 | 
			
		||||
    VM* vm = pk_current_vm;
 | 
			
		||||
    CodeObject co;
 | 
			
		||||
    pk_SourceData_ src = pk_SourceData__rcnew(source, filename, mode, false);
 | 
			
		||||
    SourceData_ src = SourceData__rcnew(source, filename, mode, false);
 | 
			
		||||
    Error* err = pk_compile(src, &co);
 | 
			
		||||
    if(err) {
 | 
			
		||||
        py_exception("SyntaxError", err->msg);
 | 
			
		||||
@ -201,8 +201,8 @@ bool py_exec(const char* source, const char* filename, enum py_CompileMode mode,
 | 
			
		||||
    if(!module) module = &vm->main;
 | 
			
		||||
 | 
			
		||||
    Frame* frame = Frame__new(&co, module, NULL, vm->stack.sp, vm->stack.sp, &co);
 | 
			
		||||
    pk_VM__push_frame(vm, frame);
 | 
			
		||||
    pk_FrameResult res = pk_VM__run_top_frame(vm);
 | 
			
		||||
    VM__push_frame(vm, frame);
 | 
			
		||||
    FrameResult res = VM__run_top_frame(vm);
 | 
			
		||||
    CodeObject__dtor(&co);
 | 
			
		||||
    PK_DECREF(src);
 | 
			
		||||
    if(res == RES_ERROR) return false;
 | 
			
		||||
@ -225,8 +225,8 @@ bool py_call(py_Ref f, int argc, py_Ref argv) {
 | 
			
		||||
bool py_callmethod(py_Ref self, py_Name name, int argc, py_Ref argv) { return -1; }
 | 
			
		||||
 | 
			
		||||
bool py_vectorcall(uint16_t argc, uint16_t kwargc) {
 | 
			
		||||
    pk_VM* vm = pk_current_vm;
 | 
			
		||||
    return pk_VM__vectorcall(vm, argc, kwargc, false) != RES_ERROR;
 | 
			
		||||
    VM* vm = pk_current_vm;
 | 
			
		||||
    return VM__vectorcall(vm, argc, kwargc, false) != RES_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
py_Ref py_retval() { return &pk_current_vm->last_retval; }
 | 
			
		||||
@ -238,8 +238,8 @@ bool pk_pushmethod(py_StackRef self, py_Name name) {
 | 
			
		||||
    py_Type type;
 | 
			
		||||
    // handle super() proxy
 | 
			
		||||
    if(py_istype(self, tp_super)) {
 | 
			
		||||
        self = py_getslot(self, 0);
 | 
			
		||||
        type = *(py_Type*)py_touserdata(self);
 | 
			
		||||
        *self = *py_getslot(self, 0);
 | 
			
		||||
    } else {
 | 
			
		||||
        type = self->type;
 | 
			
		||||
    }
 | 
			
		||||
@ -262,19 +262,18 @@ bool pk_pushmethod(py_StackRef self, py_Name name) {
 | 
			
		||||
                break;
 | 
			
		||||
            case tp_classmethod:
 | 
			
		||||
                self[0] = *py_getslot(cls_var, 0);
 | 
			
		||||
                self[1] = c11__getitem(pk_TypeInfo, &pk_current_vm->types, type).self;
 | 
			
		||||
                self[1] = c11__getitem(py_TypeInfo, &pk_current_vm->types, type).self;
 | 
			
		||||
                break;
 | 
			
		||||
            default: c11__unreachedable();
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    // TODO: __getattr__ fallback
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
py_Ref py_tpfindmagic(py_Type t, py_Name name) {
 | 
			
		||||
    assert(py_ismagicname(name));
 | 
			
		||||
    pk_TypeInfo* types = (pk_TypeInfo*)pk_current_vm->types.data;
 | 
			
		||||
    py_TypeInfo* types = (py_TypeInfo*)pk_current_vm->types.data;
 | 
			
		||||
    do {
 | 
			
		||||
        py_Ref f = &types[t].magic[name];
 | 
			
		||||
        if(!py_isnil(f)) return f;
 | 
			
		||||
@ -284,7 +283,7 @@ py_Ref py_tpfindmagic(py_Type t, py_Name name) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
py_Ref py_tpfindname(py_Type t, py_Name name) {
 | 
			
		||||
    pk_TypeInfo* types = (pk_TypeInfo*)pk_current_vm->types.data;
 | 
			
		||||
    py_TypeInfo* types = (py_TypeInfo*)pk_current_vm->types.data;
 | 
			
		||||
    do {
 | 
			
		||||
        py_Ref res = py_getdict(&types[t].self, name);
 | 
			
		||||
        if(res) return res;
 | 
			
		||||
@ -295,20 +294,20 @@ py_Ref py_tpfindname(py_Type t, py_Name name) {
 | 
			
		||||
 | 
			
		||||
py_Ref py_tpmagic(py_Type type, py_Name name) {
 | 
			
		||||
    assert(py_ismagicname(name));
 | 
			
		||||
    pk_VM* vm = pk_current_vm;
 | 
			
		||||
    return &c11__at(pk_TypeInfo, &vm->types, type)->magic[name];
 | 
			
		||||
    VM* vm = pk_current_vm;
 | 
			
		||||
    return &c11__at(py_TypeInfo, &vm->types, type)->magic[name];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
py_Ref py_tpobject(py_Type type) {
 | 
			
		||||
    assert(type);
 | 
			
		||||
    pk_VM* vm = pk_current_vm;
 | 
			
		||||
    return &c11__at(pk_TypeInfo, &vm->types, type)->self;
 | 
			
		||||
    VM* vm = pk_current_vm;
 | 
			
		||||
    return &c11__at(py_TypeInfo, &vm->types, type)->self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
    VM* vm = pk_current_vm;
 | 
			
		||||
    py_Name name = c11__at(py_TypeInfo, &vm->types, type)->name;
 | 
			
		||||
    return py_name2str(name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -325,7 +324,7 @@ bool pk_callmagic(py_Name name, int argc, py_Ref argv) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool StopIteration() {
 | 
			
		||||
    pk_VM* vm = pk_current_vm;
 | 
			
		||||
    VM* vm = pk_current_vm;
 | 
			
		||||
    assert(!vm->is_stopiteration);  // flag is already set
 | 
			
		||||
    vm->is_stopiteration = true;
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
@ -4,15 +4,16 @@
 | 
			
		||||
#include "pocketpy/objects/object.h"
 | 
			
		||||
#include "pocketpy/common/sstream.h"
 | 
			
		||||
#include "pocketpy/interpreter/vm.h"
 | 
			
		||||
#include "pocketpy/common/_generated.h"
 | 
			
		||||
 | 
			
		||||
py_Ref py_getmodule(const char* path) {
 | 
			
		||||
    pk_VM* vm = pk_current_vm;
 | 
			
		||||
    return pk_NameDict__try_get(&vm->modules, py_name(path));
 | 
			
		||||
    VM* vm = pk_current_vm;
 | 
			
		||||
    return NameDict__try_get(&vm->modules, py_name(path));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
py_Ref py_newmodule(const char* path) {
 | 
			
		||||
    pk_ManagedHeap* heap = &pk_current_vm->heap;
 | 
			
		||||
    PyObject* obj = pk_ManagedHeap__new(heap, tp_module, -1, 0);
 | 
			
		||||
    ManagedHeap* heap = &pk_current_vm->heap;
 | 
			
		||||
    PyObject* obj = ManagedHeap__new(heap, tp_module, -1, 0);
 | 
			
		||||
 | 
			
		||||
    py_Ref r0 = py_pushtmp();
 | 
			
		||||
    py_Ref r1 = py_pushtmp();
 | 
			
		||||
@ -43,28 +44,61 @@ py_Ref py_newmodule(const char* path) {
 | 
			
		||||
    // we do not allow override in order to avoid memory leak
 | 
			
		||||
    // it is because Module objects are not garbage collected
 | 
			
		||||
    py_Name path_name = py_name(path);
 | 
			
		||||
    bool exists = pk_NameDict__contains(&pk_current_vm->modules, path_name);
 | 
			
		||||
    bool exists = NameDict__contains(&pk_current_vm->modules, path_name);
 | 
			
		||||
    if(exists) c11__abort("module '%s' already exists", path);
 | 
			
		||||
    pk_NameDict__set(&pk_current_vm->modules, path_name, *r0);
 | 
			
		||||
    NameDict__set(&pk_current_vm->modules, path_name, *r0);
 | 
			
		||||
 | 
			
		||||
    py_shrink(2);
 | 
			
		||||
    return py_getmodule(path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool py_import(const char* path_cstr) {
 | 
			
		||||
    pk_VM* vm = pk_current_vm;
 | 
			
		||||
int py_import(const char* path_cstr) {
 | 
			
		||||
    // printf("importing %s\n", path_cstr);
 | 
			
		||||
 | 
			
		||||
    VM* vm = pk_current_vm;
 | 
			
		||||
    c11_sv path = {path_cstr, strlen(path_cstr)};
 | 
			
		||||
    if(path.size == 0) return ValueError("empty module name");
 | 
			
		||||
 | 
			
		||||
    if(path.data[0] == '.') {
 | 
			
		||||
        // try relative import
 | 
			
		||||
        py_Ref package = py_getdict(&vm->top_frame->module, __package__);
 | 
			
		||||
        int dot_count = 1;
 | 
			
		||||
        while(dot_count < path.size && path.data[dot_count] == '.')
 | 
			
		||||
            dot_count++;
 | 
			
		||||
 | 
			
		||||
        c11_sv top_filename = c11_string__sv(vm->top_frame->co->src->filename);
 | 
			
		||||
        int is_init = c11_sv__endswith(top_filename, (c11_sv){"__init__.py", 11});
 | 
			
		||||
 | 
			
		||||
        py_Ref package = py_getdict(&vm->top_frame->module, __path__);
 | 
			
		||||
        c11_sv package_sv = py_tosv(package);
 | 
			
		||||
        if(package_sv.size == 0) return ImportError("relative import %q with no known parent package", path);
 | 
			
		||||
        c11_string* new_path = c11_string__new3("%v.%v", package_sv, path);
 | 
			
		||||
        bool ok = py_import(new_path->data);
 | 
			
		||||
        if(package_sv.size == 0) {
 | 
			
		||||
            return ImportError("attempted relative import with no known parent package");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        c11_vector /* T=c11_sv */ cpnts = c11_sv__split(package_sv, '.');
 | 
			
		||||
        for(int i = is_init; i < dot_count; i++) {
 | 
			
		||||
            if(cpnts.count == 0)
 | 
			
		||||
                return ImportError("attempted relative import beyond top-level package");
 | 
			
		||||
            c11_vector__pop(&cpnts);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(dot_count < path.size) {
 | 
			
		||||
            c11_sv last_cpnt = c11_sv__slice(path, dot_count);
 | 
			
		||||
            c11_vector__push(c11_sv, &cpnts, last_cpnt);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // join cpnts
 | 
			
		||||
        c11_sbuf buf;
 | 
			
		||||
        c11_sbuf__ctor(&buf);
 | 
			
		||||
        for(int i = 0; i < cpnts.count; i++) {
 | 
			
		||||
            if(i > 0) c11_sbuf__write_char(&buf, '.');
 | 
			
		||||
            c11_sbuf__write_sv(&buf, c11__getitem(c11_sv, &cpnts, i));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        c11_vector__dtor(&cpnts);
 | 
			
		||||
        c11_string* new_path = c11_sbuf__submit(&buf);
 | 
			
		||||
        int res = py_import(new_path->data);
 | 
			
		||||
        c11_string__delete(new_path);
 | 
			
		||||
        return ok;
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    assert(path.data[0] != '.' && path.data[path.size - 1] != '.');
 | 
			
		||||
@ -72,67 +106,54 @@ bool py_import(const char* path_cstr) {
 | 
			
		||||
    // check existing module
 | 
			
		||||
    py_TmpRef ext_mod = py_getmodule(path.data);
 | 
			
		||||
    if(ext_mod) {
 | 
			
		||||
        py_Ref is_pending = py_getdict(ext_mod, __module_is_pending__);
 | 
			
		||||
        if(is_pending) return ImportError("circular import detected");
 | 
			
		||||
        py_assign(py_retval(), ext_mod);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // vector<std::string_view> path_cpnts = path.split('.');
 | 
			
		||||
    // // check circular import
 | 
			
		||||
    // if(__import_context.pending.size() > 128) { ImportError("maximum recursion depth exceeded
 | 
			
		||||
    // while importing"); }
 | 
			
		||||
 | 
			
		||||
    // try import
 | 
			
		||||
    c11_string* slashed_path = c11_sv__replace(path, '.', PK_PLATFORM_SEP);
 | 
			
		||||
    c11_string* filename = c11_string__new3("%s.py", slashed_path->data);
 | 
			
		||||
 | 
			
		||||
    c11_string* filename = c11_string__new3("site-packages/%s.py", slashed_path->data);
 | 
			
		||||
    int size;
 | 
			
		||||
    unsigned char* data = py_vfsread(filename->data, &size);
 | 
			
		||||
    if(data != NULL) goto __SUCCESS;
 | 
			
		||||
    bool need_free = true;
 | 
			
		||||
    const char* data = load_kPythonLib(path_cstr);
 | 
			
		||||
    if(data != NULL) {
 | 
			
		||||
        need_free = false;
 | 
			
		||||
        goto __SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    c11_string__delete(filename);
 | 
			
		||||
    filename = c11_string__new3("site-packages/%s/__init__.py", slashed_path->data);
 | 
			
		||||
    data = py_vfsread(filename->data, &size);
 | 
			
		||||
    if(data != NULL) goto __SUCCESS;
 | 
			
		||||
 | 
			
		||||
    c11_string__delete(filename);
 | 
			
		||||
    filename = c11_string__new3("%s.py", slashed_path->data);
 | 
			
		||||
    data = vm->import_file(slashed_path->data, &size);
 | 
			
		||||
    data = vm->import_file(filename->data);
 | 
			
		||||
    if(data != NULL) goto __SUCCESS;
 | 
			
		||||
 | 
			
		||||
    c11_string__delete(filename);
 | 
			
		||||
    filename = c11_string__new3("%s/__init__.py", slashed_path->data);
 | 
			
		||||
    data = vm->import_file(slashed_path->data, &size);
 | 
			
		||||
    data = vm->import_file(filename->data);
 | 
			
		||||
    if(data != NULL) goto __SUCCESS;
 | 
			
		||||
 | 
			
		||||
    c11_string__delete(filename);
 | 
			
		||||
    c11_string__delete(slashed_path);
 | 
			
		||||
    return ImportError("module %q not found", path);
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
__SUCCESS:
 | 
			
		||||
    py_push(py_newmodule(path_cstr));
 | 
			
		||||
    py_Ref mod = py_peek(-1);
 | 
			
		||||
    py_setdict(mod, __module_is_pending__, py_True);
 | 
			
		||||
    bool ok = py_exec((const char*)data, filename->data, EXEC_MODE, mod);
 | 
			
		||||
    py_deldict(mod, __module_is_pending__);
 | 
			
		||||
    py_assign(py_retval(), mod);
 | 
			
		||||
    py_pop();
 | 
			
		||||
 | 
			
		||||
    c11_string__delete(filename);
 | 
			
		||||
    c11_string__delete(slashed_path);
 | 
			
		||||
    free(data);
 | 
			
		||||
    return ok;
 | 
			
		||||
    if(need_free) free((void*)data);
 | 
			
		||||
    return ok ? 1 : -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//////////////////////////
 | 
			
		||||
 | 
			
		||||
static bool _py_builtins__repr(int argc, py_Ref argv) {
 | 
			
		||||
static bool builtins__repr(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    return py_repr(argv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_builtins__exit(int argc, py_Ref argv) {
 | 
			
		||||
static bool builtins__exit(int argc, py_Ref argv) {
 | 
			
		||||
    int code = 0;
 | 
			
		||||
    if(argc > 1) return TypeError("exit() takes at most 1 argument");
 | 
			
		||||
    if(argc == 1) {
 | 
			
		||||
@ -144,12 +165,12 @@ static bool _py_builtins__exit(int argc, py_Ref argv) {
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_builtins__len(int argc, py_Ref argv) {
 | 
			
		||||
static bool builtins__len(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    return py_len(argv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_builtins__reversed(int argc, py_Ref argv) {
 | 
			
		||||
static bool builtins__reversed(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    // convert _0 to list object
 | 
			
		||||
    if(!py_tpcall(tp_list, 1, argv)) return false;
 | 
			
		||||
@ -157,7 +178,7 @@ static bool _py_builtins__reversed(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_builtins__hex(int argc, py_Ref argv) {
 | 
			
		||||
static bool builtins__hex(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    PY_CHECK_ARG_TYPE(0, tp_int);
 | 
			
		||||
 | 
			
		||||
@ -187,12 +208,12 @@ static bool _py_builtins__hex(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_builtins__iter(int argc, py_Ref argv) {
 | 
			
		||||
static bool builtins__iter(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    return py_iter(argv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_builtins__next(int argc, py_Ref argv) {
 | 
			
		||||
static bool builtins__next(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    int res = py_next(argv);
 | 
			
		||||
    if(res == -1) return false;
 | 
			
		||||
@ -200,7 +221,7 @@ static bool _py_builtins__next(int argc, py_Ref argv) {
 | 
			
		||||
    return py_exception("StopIteration", "");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_builtins__sorted(int argc, py_Ref argv) {
 | 
			
		||||
static bool builtins__sorted(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(3);
 | 
			
		||||
    // convert _0 to list object
 | 
			
		||||
    if(!py_tpcall(tp_list, 1, py_arg(0))) return false;
 | 
			
		||||
@ -217,7 +238,7 @@ static bool _py_builtins__sorted(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_builtins__hash(int argc, py_Ref argv) {
 | 
			
		||||
static bool builtins__hash(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    py_i64 val;
 | 
			
		||||
    if(!py_hash(argv, &val)) return false;
 | 
			
		||||
@ -225,28 +246,36 @@ static bool _py_builtins__hash(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_builtins__abs(int argc, py_Ref argv) {
 | 
			
		||||
static bool builtins__abs(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    return pk_callmagic(__abs__, 1, argv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_builtins__sum(int argc, py_Ref argv) {
 | 
			
		||||
static bool builtins__sum(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    int length;
 | 
			
		||||
    py_TValue* p = pk_arrayview(argv, &length);
 | 
			
		||||
    if(!p) return TypeError("sum() expects a list or tuple");
 | 
			
		||||
 | 
			
		||||
    if(!py_iter(py_arg(0))) return false;
 | 
			
		||||
    py_push(py_retval());  // iter
 | 
			
		||||
 | 
			
		||||
    py_i64 total_i64 = 0;
 | 
			
		||||
    py_f64 total_f64 = 0.0;
 | 
			
		||||
    bool is_float = false;
 | 
			
		||||
    for(int i = 0; i < length; i++) {
 | 
			
		||||
        switch(p[i].type) {
 | 
			
		||||
            case tp_int: total_i64 += p[i]._i64; break;
 | 
			
		||||
    while(true) {
 | 
			
		||||
        int res = py_next(py_peek(-1));
 | 
			
		||||
        if(res == -1) {
 | 
			
		||||
            py_pop();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        if(res == 0) break;
 | 
			
		||||
 | 
			
		||||
        py_Ref item = py_retval();
 | 
			
		||||
        switch(item->type) {
 | 
			
		||||
            case tp_int: total_i64 += item->_i64; break;
 | 
			
		||||
            case tp_float:
 | 
			
		||||
                is_float = true;
 | 
			
		||||
                total_f64 += p[i]._f64;
 | 
			
		||||
                total_f64 += item->_f64;
 | 
			
		||||
                break;
 | 
			
		||||
            default: return TypeError("sum() expects a list of numbers");
 | 
			
		||||
            default: return TypeError("sum() expects an iterable of numbers");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -255,10 +284,11 @@ static bool _py_builtins__sum(int argc, py_Ref argv) {
 | 
			
		||||
    } else {
 | 
			
		||||
        py_newint(py_retval(), total_i64);
 | 
			
		||||
    }
 | 
			
		||||
    py_pop();
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_builtins__print(int argc, py_Ref argv) {
 | 
			
		||||
static bool builtins__print(int argc, py_Ref argv) {
 | 
			
		||||
    int length;
 | 
			
		||||
    py_TValue* args = pk_arrayview(argv, &length);
 | 
			
		||||
    assert(args != NULL);
 | 
			
		||||
@ -279,44 +309,76 @@ static bool _py_builtins__print(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_NoneType__repr__(int argc, py_Ref argv) {
 | 
			
		||||
static bool NoneType__repr__(int argc, py_Ref argv) {
 | 
			
		||||
    py_newstr(py_retval(), "None");
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_builtins__exec(int argc, py_Ref argv) {
 | 
			
		||||
static bool builtins__exec(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    PY_CHECK_ARG_TYPE(0, tp_str);
 | 
			
		||||
    return py_exec(py_tostr(argv), "<exec>", EXEC_MODE, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_builtins__eval(int argc, py_Ref argv) {
 | 
			
		||||
static bool builtins__eval(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    PY_CHECK_ARG_TYPE(0, tp_str);
 | 
			
		||||
    return py_exec(py_tostr(argv), "<eval>", EVAL_MODE, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool builtins__isinstance(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    if(py_istuple(py_arg(1))) {
 | 
			
		||||
        int length = py_tuple__len(py_arg(1));
 | 
			
		||||
        for(int i = 0; i < length; i++) {
 | 
			
		||||
            py_Ref item = py_tuple__getitem(py_arg(1), i);
 | 
			
		||||
            if(!py_checktype(item, tp_type)) return false;
 | 
			
		||||
            if(py_isinstance(py_arg(0), py_totype(item))) {
 | 
			
		||||
                py_newbool(py_retval(), true);
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        py_newbool(py_retval(), false);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(!py_checktype(py_arg(1), tp_type)) return false;
 | 
			
		||||
    py_newbool(py_retval(), py_isinstance(py_arg(0), py_totype(py_arg(1))));
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool builtins__issubclass(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    if(!py_checktype(py_arg(0), tp_type)) return false;
 | 
			
		||||
    if(!py_checktype(py_arg(1), tp_type)) return false;
 | 
			
		||||
    py_newbool(py_retval(), py_issubclass(py_totype(py_arg(0)), py_totype(py_arg(1))));
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
py_TValue pk_builtins__register() {
 | 
			
		||||
    py_Ref builtins = py_newmodule("builtins");
 | 
			
		||||
    py_bindfunc(builtins, "repr", _py_builtins__repr);
 | 
			
		||||
    py_bindfunc(builtins, "exit", _py_builtins__exit);
 | 
			
		||||
    py_bindfunc(builtins, "len", _py_builtins__len);
 | 
			
		||||
    py_bindfunc(builtins, "reversed", _py_builtins__reversed);
 | 
			
		||||
    py_bindfunc(builtins, "hex", _py_builtins__hex);
 | 
			
		||||
    py_bindfunc(builtins, "iter", _py_builtins__iter);
 | 
			
		||||
    py_bindfunc(builtins, "next", _py_builtins__next);
 | 
			
		||||
    py_bindfunc(builtins, "hash", _py_builtins__hash);
 | 
			
		||||
    py_bindfunc(builtins, "abs", _py_builtins__abs);
 | 
			
		||||
    py_bindfunc(builtins, "sum", _py_builtins__sum);
 | 
			
		||||
    py_bindfunc(builtins, "repr", builtins__repr);
 | 
			
		||||
    py_bindfunc(builtins, "exit", builtins__exit);
 | 
			
		||||
    py_bindfunc(builtins, "len", builtins__len);
 | 
			
		||||
    py_bindfunc(builtins, "reversed", builtins__reversed);
 | 
			
		||||
    py_bindfunc(builtins, "hex", builtins__hex);
 | 
			
		||||
    py_bindfunc(builtins, "iter", builtins__iter);
 | 
			
		||||
    py_bindfunc(builtins, "next", builtins__next);
 | 
			
		||||
    py_bindfunc(builtins, "hash", builtins__hash);
 | 
			
		||||
    py_bindfunc(builtins, "abs", builtins__abs);
 | 
			
		||||
    py_bindfunc(builtins, "sum", builtins__sum);
 | 
			
		||||
 | 
			
		||||
    py_bindfunc(builtins, "exec", _py_builtins__exec);
 | 
			
		||||
    py_bindfunc(builtins, "eval", _py_builtins__eval);
 | 
			
		||||
    py_bindfunc(builtins, "exec", builtins__exec);
 | 
			
		||||
    py_bindfunc(builtins, "eval", builtins__eval);
 | 
			
		||||
 | 
			
		||||
    py_bind(builtins, "print(*args, sep=' ', end='\\n')", _py_builtins__print);
 | 
			
		||||
    py_bind(builtins, "sorted(iterable, key=None, reverse=False)", _py_builtins__sorted);
 | 
			
		||||
    py_bind(builtins, "print(*args, sep=' ', end='\\n')", builtins__print);
 | 
			
		||||
    py_bind(builtins, "sorted(iterable, key=None, reverse=False)", builtins__sorted);
 | 
			
		||||
 | 
			
		||||
    py_bindfunc(builtins, "isinstance", builtins__isinstance);
 | 
			
		||||
    py_bindfunc(builtins, "issubclass", builtins__issubclass);
 | 
			
		||||
 | 
			
		||||
    // None __repr__
 | 
			
		||||
    py_bindmagic(tp_NoneType, __repr__, _py_NoneType__repr__);
 | 
			
		||||
    py_bindmagic(tp_NoneType, __repr__, NoneType__repr__);
 | 
			
		||||
    return *builtins;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -326,7 +388,7 @@ py_Type pk_function__register() {
 | 
			
		||||
    return type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_nativefunc__repr(int argc, py_Ref argv) {
 | 
			
		||||
static bool nativefunc__repr(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    py_newstr(py_retval(), "<nativefunc object>");
 | 
			
		||||
    return true;
 | 
			
		||||
@ -334,6 +396,46 @@ static bool _py_nativefunc__repr(int argc, py_Ref argv) {
 | 
			
		||||
 | 
			
		||||
py_Type pk_nativefunc__register() {
 | 
			
		||||
    py_Type type = pk_newtype("nativefunc", tp_object, NULL, NULL, false, true);
 | 
			
		||||
    py_bindmagic(type, __repr__, _py_nativefunc__repr);
 | 
			
		||||
    py_bindmagic(type, __repr__, nativefunc__repr);
 | 
			
		||||
    return type;
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool super__new__(int argc, py_Ref argv) {
 | 
			
		||||
    py_Type* class_arg = py_newobject(py_retval(), tp_super, 1, sizeof(py_Type));
 | 
			
		||||
    Frame* frame = pk_current_vm->top_frame;
 | 
			
		||||
    *class_arg = 0;
 | 
			
		||||
    py_Ref self_arg = NULL;
 | 
			
		||||
    if(argc == 1) {
 | 
			
		||||
        // super()
 | 
			
		||||
        if(frame->function) {
 | 
			
		||||
            // class_arg = PK_OBJ_GET(Function, frame->_callable)._class;
 | 
			
		||||
            Function* func = PyObject__userdata(frame->function);
 | 
			
		||||
            *class_arg = *(py_Type*)PyObject__userdata(func->clazz);
 | 
			
		||||
            if(frame->locals_co->nlocals > 0) self_arg = &frame->locals[0];
 | 
			
		||||
        }
 | 
			
		||||
        if(class_arg == 0 || self_arg == NULL) return RuntimeError("super(): no arguments");
 | 
			
		||||
    } else if(argc == 3) {
 | 
			
		||||
        // super(type, obj)
 | 
			
		||||
        PY_CHECK_ARG_TYPE(1, tp_type);
 | 
			
		||||
        *class_arg = py_totype(py_arg(1));
 | 
			
		||||
        self_arg = py_arg(2);
 | 
			
		||||
        if(!py_isinstance(self_arg, *class_arg)) {
 | 
			
		||||
            return TypeError("super(type, obj): obj must be an instance of type");
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        return TypeError("super() takes 0 or 2 arguments");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    py_TypeInfo* types = pk_current_vm->types.data;
 | 
			
		||||
    *class_arg = types[*class_arg].base;
 | 
			
		||||
    if(*class_arg == 0) return RuntimeError("super(): base class is invalid");
 | 
			
		||||
 | 
			
		||||
    py_setslot(py_retval(), 0, self_arg);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
py_Type pk_super__register() {
 | 
			
		||||
    py_Type type = pk_newtype("super", tp_object, NULL, NULL, false, true);
 | 
			
		||||
    py_bindmagic(type, __new__, super__new__);
 | 
			
		||||
    return type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -61,13 +61,13 @@ bool pk_arraycontains(py_Ref self, py_Ref val) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_array_iterator__iter__(int argc, py_Ref argv) {
 | 
			
		||||
static bool array_iterator__iter__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    *py_retval() = *argv;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_array_iterator__next__(int argc, py_Ref argv) {
 | 
			
		||||
static bool array_iterator__next__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    array_iterator* ud = py_touserdata(argv);
 | 
			
		||||
    if(ud->index < ud->length) {
 | 
			
		||||
@ -79,7 +79,7 @@ static bool _py_array_iterator__next__(int argc, py_Ref argv) {
 | 
			
		||||
 | 
			
		||||
py_Type pk_array_iterator__register() {
 | 
			
		||||
    py_Type type = pk_newtype("array_iterator", tp_object, NULL, NULL, false, true);
 | 
			
		||||
    py_bindmagic(type, __iter__, _py_array_iterator__iter__);
 | 
			
		||||
    py_bindmagic(type, __next__, _py_array_iterator__next__);
 | 
			
		||||
    py_bindmagic(type, __iter__, array_iterator__iter__);
 | 
			
		||||
    py_bindmagic(type, __next__, array_iterator__next__);
 | 
			
		||||
    return type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -204,12 +204,12 @@ static DictEntry* DictIterator__next(DictIterator* self) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
///////////////////////////////
 | 
			
		||||
static bool _py_dict__new__(int argc, py_Ref argv) {
 | 
			
		||||
static bool dict__new__(int argc, py_Ref argv) {
 | 
			
		||||
    py_newdict(py_retval());
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_dict__init__(int argc, py_Ref argv) {
 | 
			
		||||
static bool dict__init__(int argc, py_Ref argv) {
 | 
			
		||||
    if(argc > 2) return TypeError("dict.__init__() takes at most 2 arguments (%d given)", argc);
 | 
			
		||||
    if(argc == 1) return true;
 | 
			
		||||
    assert(argc == 2);
 | 
			
		||||
@ -228,7 +228,7 @@ static bool _py_dict__init__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_dict__getitem__(int argc, py_Ref argv) {
 | 
			
		||||
static bool dict__getitem__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    Dict* self = py_touserdata(argv);
 | 
			
		||||
    DictEntry* entry;
 | 
			
		||||
@ -240,20 +240,20 @@ static bool _py_dict__getitem__(int argc, py_Ref argv) {
 | 
			
		||||
    return KeyError(py_arg(1));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_dict__setitem__(int argc, py_Ref argv) {
 | 
			
		||||
static bool dict__setitem__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(3);
 | 
			
		||||
    Dict* self = py_touserdata(argv);
 | 
			
		||||
    return Dict__set(self, py_arg(1), py_arg(2));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_dict__delitem__(int argc, py_Ref argv) {
 | 
			
		||||
static bool dict__delitem__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    Dict* self = py_touserdata(argv);
 | 
			
		||||
    if(!Dict__pop(self, py_arg(1))) return false;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_dict__contains__(int argc, py_Ref argv) {
 | 
			
		||||
static bool dict__contains__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    Dict* self = py_touserdata(argv);
 | 
			
		||||
    DictEntry* entry;
 | 
			
		||||
@ -262,14 +262,14 @@ static bool _py_dict__contains__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_dict__len__(int argc, py_Ref argv) {
 | 
			
		||||
static bool dict__len__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    Dict* self = py_touserdata(argv);
 | 
			
		||||
    py_newint(py_retval(), self->length);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_dict__repr__(int argc, py_Ref argv) {
 | 
			
		||||
static bool dict__repr__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    Dict* self = py_touserdata(argv);
 | 
			
		||||
    c11_sbuf buf;
 | 
			
		||||
@ -292,7 +292,7 @@ static bool _py_dict__repr__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_dict__eq__(int argc, py_Ref argv) {
 | 
			
		||||
static bool dict__eq__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    Dict* self = py_touserdata(py_arg(0));
 | 
			
		||||
    if(!py_isdict(py_arg(1))) {
 | 
			
		||||
@ -326,8 +326,8 @@ static bool _py_dict__eq__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_dict__ne__(int argc, py_Ref argv) {
 | 
			
		||||
    if(!_py_dict__eq__(argc, argv)) return false;
 | 
			
		||||
static bool dict__ne__(int argc, py_Ref argv) {
 | 
			
		||||
    if(!dict__eq__(argc, argv)) return false;
 | 
			
		||||
    if(py_isbool(py_retval())) {
 | 
			
		||||
        bool res = py_tobool(py_retval());
 | 
			
		||||
        py_newbool(py_retval(), !res);
 | 
			
		||||
@ -335,14 +335,14 @@ static bool _py_dict__ne__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_dict__clear(int argc, py_Ref argv) {
 | 
			
		||||
static bool dict__clear(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    Dict* self = py_touserdata(argv);
 | 
			
		||||
    Dict__clear(self);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_dict__copy(int argc, py_Ref argv) {
 | 
			
		||||
static bool dict__copy(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    Dict* self = py_touserdata(argv);
 | 
			
		||||
    Dict* new_dict = py_newobject(py_retval(), tp_dict, 0, sizeof(Dict));
 | 
			
		||||
@ -355,7 +355,7 @@ static bool _py_dict__copy(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_dict__update(int argc, py_Ref argv) {
 | 
			
		||||
static bool dict__update(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    PY_CHECK_ARG_TYPE(1, tp_dict);
 | 
			
		||||
    Dict* self = py_touserdata(argv);
 | 
			
		||||
@ -368,7 +368,7 @@ static bool _py_dict__update(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_dict__get(int argc, py_Ref argv) {
 | 
			
		||||
static bool dict__get(int argc, py_Ref argv) {
 | 
			
		||||
    Dict* self = py_touserdata(argv);
 | 
			
		||||
    if(argc > 3) return TypeError("get() takes at most 3 arguments (%d given)", argc);
 | 
			
		||||
    py_Ref default_val = argc == 3 ? py_arg(2) : py_None;
 | 
			
		||||
@ -378,7 +378,7 @@ static bool _py_dict__get(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_dict__pop(int argc, py_Ref argv) {
 | 
			
		||||
static bool dict__pop(int argc, py_Ref argv) {
 | 
			
		||||
    Dict* self = py_touserdata(argv);
 | 
			
		||||
    if(argc < 2 || argc > 3) return TypeError("pop() takes 2 or 3 arguments (%d given)", argc);
 | 
			
		||||
    py_Ref default_val = argc == 3 ? py_arg(2) : py_None;
 | 
			
		||||
@ -387,7 +387,7 @@ static bool _py_dict__pop(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_dict__items(int argc, py_Ref argv) {
 | 
			
		||||
static bool dict__items(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    Dict* self = py_touserdata(argv);
 | 
			
		||||
    DictIterator* ud = py_newobject(py_retval(), tp_dict_items, 1, sizeof(DictIterator));
 | 
			
		||||
@ -396,7 +396,7 @@ static bool _py_dict__items(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_dict__keys(int argc, py_Ref argv) {
 | 
			
		||||
static bool dict__keys(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    Dict* self = py_touserdata(argv);
 | 
			
		||||
    py_newtuple(py_retval(), self->length);
 | 
			
		||||
@ -412,7 +412,7 @@ static bool _py_dict__keys(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_dict__values(int argc, py_Ref argv) {
 | 
			
		||||
static bool dict__values(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    Dict* self = py_touserdata(argv);
 | 
			
		||||
    py_newtuple(py_retval(), self->length);
 | 
			
		||||
@ -431,38 +431,38 @@ static bool _py_dict__values(int argc, py_Ref argv) {
 | 
			
		||||
py_Type pk_dict__register() {
 | 
			
		||||
    py_Type type = pk_newtype("dict", tp_object, NULL, (void (*)(void*))Dict__dtor, false, false);
 | 
			
		||||
 | 
			
		||||
    py_bindmagic(type, __new__, _py_dict__new__);
 | 
			
		||||
    py_bindmagic(type, __init__, _py_dict__init__);
 | 
			
		||||
    py_bindmagic(type, __getitem__, _py_dict__getitem__);
 | 
			
		||||
    py_bindmagic(type, __setitem__, _py_dict__setitem__);
 | 
			
		||||
    py_bindmagic(type, __delitem__, _py_dict__delitem__);
 | 
			
		||||
    py_bindmagic(type, __contains__, _py_dict__contains__);
 | 
			
		||||
    py_bindmagic(type, __len__, _py_dict__len__);
 | 
			
		||||
    py_bindmagic(type, __repr__, _py_dict__repr__);
 | 
			
		||||
    py_bindmagic(type, __eq__, _py_dict__eq__);
 | 
			
		||||
    py_bindmagic(type, __ne__, _py_dict__ne__);
 | 
			
		||||
    py_bindmagic(type, __new__, dict__new__);
 | 
			
		||||
    py_bindmagic(type, __init__, dict__init__);
 | 
			
		||||
    py_bindmagic(type, __getitem__, dict__getitem__);
 | 
			
		||||
    py_bindmagic(type, __setitem__, dict__setitem__);
 | 
			
		||||
    py_bindmagic(type, __delitem__, dict__delitem__);
 | 
			
		||||
    py_bindmagic(type, __contains__, dict__contains__);
 | 
			
		||||
    py_bindmagic(type, __len__, dict__len__);
 | 
			
		||||
    py_bindmagic(type, __repr__, dict__repr__);
 | 
			
		||||
    py_bindmagic(type, __eq__, dict__eq__);
 | 
			
		||||
    py_bindmagic(type, __ne__, dict__ne__);
 | 
			
		||||
 | 
			
		||||
    py_bindmethod(type, "clear", _py_dict__clear);
 | 
			
		||||
    py_bindmethod(type, "copy", _py_dict__copy);
 | 
			
		||||
    py_bindmethod(type, "update", _py_dict__update);
 | 
			
		||||
    py_bindmethod(type, "get", _py_dict__get);
 | 
			
		||||
    py_bindmethod(type, "pop", _py_dict__pop);
 | 
			
		||||
    py_bindmethod(type, "items", _py_dict__items);
 | 
			
		||||
    py_bindmethod(type, "keys", _py_dict__keys);
 | 
			
		||||
    py_bindmethod(type, "values", _py_dict__values);
 | 
			
		||||
    py_bindmethod(type, "clear", dict__clear);
 | 
			
		||||
    py_bindmethod(type, "copy", dict__copy);
 | 
			
		||||
    py_bindmethod(type, "update", dict__update);
 | 
			
		||||
    py_bindmethod(type, "get", dict__get);
 | 
			
		||||
    py_bindmethod(type, "pop", dict__pop);
 | 
			
		||||
    py_bindmethod(type, "items", dict__items);
 | 
			
		||||
    py_bindmethod(type, "keys", dict__keys);
 | 
			
		||||
    py_bindmethod(type, "values", dict__values);
 | 
			
		||||
 | 
			
		||||
    py_setdict(py_tpobject(type), __hash__, py_None);
 | 
			
		||||
    return type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//////////////////////////
 | 
			
		||||
static bool _py_dict_items__iter__(int argc, py_Ref argv) {
 | 
			
		||||
static bool dict_items__iter__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    *py_retval() = *argv;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_dict_items__next__(int argc, py_Ref argv) {
 | 
			
		||||
static bool dict_items__next__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    DictIterator* iter = py_touserdata(py_arg(0));
 | 
			
		||||
    DictEntry* entry = (DictIterator__next(iter));
 | 
			
		||||
@ -477,8 +477,8 @@ static bool _py_dict_items__next__(int argc, py_Ref argv) {
 | 
			
		||||
 | 
			
		||||
py_Type pk_dict_items__register() {
 | 
			
		||||
    py_Type type = pk_newtype("dict_items", tp_object, NULL, NULL, false, true);
 | 
			
		||||
    py_bindmagic(type, __iter__, _py_dict_items__iter__);
 | 
			
		||||
    py_bindmagic(type, __next__, _py_dict_items__next__);
 | 
			
		||||
    py_bindmagic(type, __iter__, dict_items__iter__);
 | 
			
		||||
    py_bindmagic(type, __next__, dict_items__next__);
 | 
			
		||||
    return type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -524,7 +524,7 @@ int py_dict__len(py_Ref self) {
 | 
			
		||||
    return ud->length;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool py_dict__apply(py_Ref self, bool (*f)(py_Ref, py_Ref, void *), void *ctx){
 | 
			
		||||
bool py_dict__apply(py_Ref self, bool (*f)(py_Ref, py_Ref, void*), void* ctx) {
 | 
			
		||||
    Dict* ud = py_touserdata(self);
 | 
			
		||||
    for(int i = 0; i < ud->entries.count; i++) {
 | 
			
		||||
        DictEntry* entry = c11__at(DictEntry, &ud->entries, i);
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@
 | 
			
		||||
#include "pocketpy/common/sstream.h"
 | 
			
		||||
 | 
			
		||||
typedef struct BaseExceptionFrame {
 | 
			
		||||
    pk_SourceData_ src;
 | 
			
		||||
    SourceData_ src;
 | 
			
		||||
    int lineno;
 | 
			
		||||
    c11_string* name;
 | 
			
		||||
} BaseExceptionFrame;
 | 
			
		||||
@ -31,7 +31,7 @@ int py_BaseException__get_lineno(py_Ref self, const CodeObject* code) {
 | 
			
		||||
    return ud->lineno_backup;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void py_BaseException__stpush(py_Ref self, pk_SourceData_ src, int lineno, const char* func_name) {
 | 
			
		||||
void py_BaseException__stpush(py_Ref self, SourceData_ src, int lineno, const char* func_name) {
 | 
			
		||||
    BaseException* ud = py_touserdata(self);
 | 
			
		||||
    if(ud->stacktrace.count >= 7) return;
 | 
			
		||||
    BaseExceptionFrame* frame = c11_vector__emplace(&ud->stacktrace);
 | 
			
		||||
@ -111,10 +111,19 @@ py_Type pk_Exception__register() {
 | 
			
		||||
 | 
			
		||||
//////////////////////////////////////////////////
 | 
			
		||||
bool py_checkexc() {
 | 
			
		||||
    pk_VM* vm = pk_current_vm;
 | 
			
		||||
    VM* vm = pk_current_vm;
 | 
			
		||||
    return !py_isnil(&vm->curr_exception);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void py_clearexc(py_StackRef p0) {
 | 
			
		||||
    VM* vm = pk_current_vm;
 | 
			
		||||
    vm->last_retval = *py_NIL;
 | 
			
		||||
    vm->curr_exception = *py_NIL;
 | 
			
		||||
    vm->is_stopiteration = false;
 | 
			
		||||
    vm->__curr_class = NULL;
 | 
			
		||||
    if(p0) vm->stack.sp = p0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void py_printexc() {
 | 
			
		||||
    char* msg = py_formatexc();
 | 
			
		||||
    if(!msg) return;
 | 
			
		||||
@ -124,7 +133,7 @@ void py_printexc() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char* py_formatexc() {
 | 
			
		||||
    pk_VM* vm = pk_current_vm;
 | 
			
		||||
    VM* vm = pk_current_vm;
 | 
			
		||||
    if(py_isnil(&vm->curr_exception)) return NULL;
 | 
			
		||||
    c11_sbuf ss;
 | 
			
		||||
    c11_sbuf__ctor(&ss);
 | 
			
		||||
@ -135,7 +144,7 @@ char* py_formatexc() {
 | 
			
		||||
 | 
			
		||||
    for(int i = ud->stacktrace.count - 1; i >= 0; i--) {
 | 
			
		||||
        BaseExceptionFrame* frame = c11__at(BaseExceptionFrame, &ud->stacktrace, i);
 | 
			
		||||
        pk_SourceData__snapshot(frame->src,
 | 
			
		||||
        SourceData__snapshot(frame->src,
 | 
			
		||||
                                &ss,
 | 
			
		||||
                                frame->lineno,
 | 
			
		||||
                                NULL,
 | 
			
		||||
@ -182,7 +191,7 @@ bool py_exception(const char* name, const char* fmt, ...) {
 | 
			
		||||
 | 
			
		||||
bool py_raise(py_Ref exc) {
 | 
			
		||||
    assert(py_isinstance(exc, tp_BaseException));
 | 
			
		||||
    pk_VM* vm = pk_current_vm;
 | 
			
		||||
    VM* vm = pk_current_vm;
 | 
			
		||||
    vm->curr_exception = *exc;
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -65,14 +65,14 @@ void py_list__reverse(py_Ref self) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////
 | 
			
		||||
static bool _py_list__len__(int argc, py_Ref argv) {
 | 
			
		||||
static bool 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_list__eq__(int argc, py_Ref argv) {
 | 
			
		||||
static bool list__eq__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    if(py_istype(py_arg(1), tp_list)) {
 | 
			
		||||
        int length0, length1;
 | 
			
		||||
@ -87,8 +87,8 @@ static bool _py_list__eq__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_list__ne__(int argc, py_Ref argv) {
 | 
			
		||||
    if(!_py_list__eq__(argc, argv)) return false;
 | 
			
		||||
static bool list__ne__(int argc, py_Ref argv) {
 | 
			
		||||
    if(!list__eq__(argc, argv)) return false;
 | 
			
		||||
    if(py_isbool(py_retval())) {
 | 
			
		||||
        bool res = py_tobool(py_retval());
 | 
			
		||||
        py_newbool(py_retval(), !res);
 | 
			
		||||
@ -96,7 +96,7 @@ static bool _py_list__ne__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_list__new__(int argc, py_Ref argv) {
 | 
			
		||||
static bool list__new__(int argc, py_Ref argv) {
 | 
			
		||||
    if(argc == 1) {
 | 
			
		||||
        py_newlist(py_retval());
 | 
			
		||||
        return true;
 | 
			
		||||
@ -120,7 +120,7 @@ static bool _py_list__new__(int argc, py_Ref argv) {
 | 
			
		||||
        py_newlist(list);
 | 
			
		||||
        while(true) {
 | 
			
		||||
            int res = py_next(iter);
 | 
			
		||||
            if(res == -1){
 | 
			
		||||
            if(res == -1) {
 | 
			
		||||
                py_shrink(2);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
@ -134,7 +134,7 @@ static bool _py_list__new__(int argc, py_Ref argv) {
 | 
			
		||||
    return TypeError("list() takes at most 1 argument");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_list__getitem__(int argc, py_Ref argv) {
 | 
			
		||||
static bool list__getitem__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    List* self = py_touserdata(py_arg(0));
 | 
			
		||||
    py_Ref _1 = py_arg(1);
 | 
			
		||||
@ -158,7 +158,7 @@ static bool _py_list__getitem__(int argc, py_Ref argv) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_list__setitem__(int argc, py_Ref argv) {
 | 
			
		||||
static bool list__setitem__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(3);
 | 
			
		||||
    PY_CHECK_ARG_TYPE(1, tp_int);
 | 
			
		||||
    List* self = py_touserdata(py_arg(0));
 | 
			
		||||
@ -168,7 +168,7 @@ static bool _py_list__setitem__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_list__delitem__(int argc, py_Ref argv) {
 | 
			
		||||
static bool list__delitem__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    PY_CHECK_ARG_TYPE(1, tp_int);
 | 
			
		||||
    List* self = py_touserdata(py_arg(0));
 | 
			
		||||
@ -179,7 +179,7 @@ static bool _py_list__delitem__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_list__add__(int argc, py_Ref argv) {
 | 
			
		||||
static bool list__add__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    py_Ref _0 = py_arg(0);
 | 
			
		||||
    py_Ref _1 = py_arg(1);
 | 
			
		||||
@ -196,7 +196,7 @@ static bool _py_list__add__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_list__mul__(int argc, py_Ref argv) {
 | 
			
		||||
static bool list__mul__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    py_Ref _0 = py_arg(0);
 | 
			
		||||
    py_Ref _1 = py_arg(1);
 | 
			
		||||
@ -214,16 +214,16 @@ static bool _py_list__mul__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_list__rmul__(int argc, py_Ref argv) { return _py_list__mul__(argc, argv); }
 | 
			
		||||
static bool list__rmul__(int argc, py_Ref argv) { return list__mul__(argc, argv); }
 | 
			
		||||
 | 
			
		||||
static bool _py_list__append(int argc, py_Ref argv) {
 | 
			
		||||
static bool list__append(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    py_list__append(py_arg(0), py_arg(1));
 | 
			
		||||
    py_newnone(py_retval());
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_list__repr__(int argc, py_Ref argv) {
 | 
			
		||||
static bool list__repr__(int argc, py_Ref argv) {
 | 
			
		||||
    List* self = py_touserdata(py_arg(0));
 | 
			
		||||
    c11_sbuf buf;
 | 
			
		||||
    c11_sbuf__ctor(&buf);
 | 
			
		||||
@ -243,7 +243,7 @@ static bool _py_list__repr__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_list__extend(int argc, py_Ref argv) {
 | 
			
		||||
static bool list__extend(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    List* self = py_touserdata(py_arg(0));
 | 
			
		||||
    PY_CHECK_ARG_TYPE(1, tp_list);
 | 
			
		||||
@ -253,7 +253,7 @@ static bool _py_list__extend(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_list__count(int argc, py_Ref argv) {
 | 
			
		||||
static bool list__count(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    int count = 0;
 | 
			
		||||
    for(int i = 0; i < py_list__len(py_arg(0)); i++) {
 | 
			
		||||
@ -265,14 +265,14 @@ static bool _py_list__count(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_list__clear(int argc, py_Ref argv) {
 | 
			
		||||
static bool list__clear(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    py_list__clear(py_arg(0));
 | 
			
		||||
    py_newnone(py_retval());
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_list__copy(int argc, py_Ref argv) {
 | 
			
		||||
static bool list__copy(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    py_newlist(py_retval());
 | 
			
		||||
    List* self = py_touserdata(py_arg(0));
 | 
			
		||||
@ -281,7 +281,7 @@ static bool _py_list__copy(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_list__index(int argc, py_Ref argv) {
 | 
			
		||||
static bool list__index(int argc, py_Ref argv) {
 | 
			
		||||
    if(argc > 3) return TypeError("index() takes at most 3 arguments");
 | 
			
		||||
    int start = 0;
 | 
			
		||||
    if(argc == 3) {
 | 
			
		||||
@ -299,7 +299,7 @@ static bool _py_list__index(int argc, py_Ref argv) {
 | 
			
		||||
    return ValueError("list.index(x): x not in list");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_list__reverse(int argc, py_Ref argv) {
 | 
			
		||||
static bool list__reverse(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    List* self = py_touserdata(py_arg(0));
 | 
			
		||||
    c11__reverse(py_TValue, self);
 | 
			
		||||
@ -307,7 +307,7 @@ static bool _py_list__reverse(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_list__remove(int argc, py_Ref argv) {
 | 
			
		||||
static bool list__remove(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    for(int i = 0; i < py_list__len(py_arg(0)); i++) {
 | 
			
		||||
        int res = py_equal(py_list__getitem(py_arg(0), i), py_arg(1));
 | 
			
		||||
@ -321,7 +321,7 @@ static bool _py_list__remove(int argc, py_Ref argv) {
 | 
			
		||||
    return ValueError("list.remove(x): x not in list");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_list__pop(int argc, py_Ref argv) {
 | 
			
		||||
static bool list__pop(int argc, py_Ref argv) {
 | 
			
		||||
    int index;
 | 
			
		||||
    if(argc == 1) {
 | 
			
		||||
        index = -1;
 | 
			
		||||
@ -339,7 +339,7 @@ static bool _py_list__pop(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_list__insert(int argc, py_Ref argv) {
 | 
			
		||||
static bool list__insert(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(3);
 | 
			
		||||
    PY_CHECK_ARG_TYPE(1, tp_int);
 | 
			
		||||
    List* self = py_touserdata(py_arg(0));
 | 
			
		||||
@ -352,9 +352,9 @@ static bool _py_list__insert(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _py_lt_with_key(py_TValue* a, py_TValue* b, py_TValue* key) {
 | 
			
		||||
static int lt_with_key(py_TValue* a, py_TValue* b, py_TValue* key) {
 | 
			
		||||
    if(!key) return py_less(a, b);
 | 
			
		||||
    pk_VM* vm = pk_current_vm;
 | 
			
		||||
    VM* vm = pk_current_vm;
 | 
			
		||||
    // project a
 | 
			
		||||
    py_push(key);
 | 
			
		||||
    py_pushnil();
 | 
			
		||||
@ -375,7 +375,7 @@ static int _py_lt_with_key(py_TValue* a, py_TValue* b, py_TValue* key) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// sort(self, key=None, reverse=False)
 | 
			
		||||
static bool _py_list__sort(int argc, py_Ref argv) {
 | 
			
		||||
static bool list__sort(int argc, py_Ref argv) {
 | 
			
		||||
    List* self = py_touserdata(py_arg(0));
 | 
			
		||||
 | 
			
		||||
    py_Ref key = py_arg(1);
 | 
			
		||||
@ -384,7 +384,7 @@ static bool _py_list__sort(int argc, py_Ref argv) {
 | 
			
		||||
    bool ok = c11__stable_sort(self->data,
 | 
			
		||||
                               self->count,
 | 
			
		||||
                               sizeof(py_TValue),
 | 
			
		||||
                               (int (*)(const void*, const void*, void*))_py_lt_with_key,
 | 
			
		||||
                               (int (*)(const void*, const void*, void*))lt_with_key,
 | 
			
		||||
                               key);
 | 
			
		||||
    if(!ok) return false;
 | 
			
		||||
 | 
			
		||||
@ -395,12 +395,12 @@ static bool _py_list__sort(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_list__iter__(int argc, py_Ref argv) {
 | 
			
		||||
static bool list__iter__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    return pk_arrayiter(argv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_list__contains__(int argc, py_Ref argv) {
 | 
			
		||||
static bool list__contains__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    return pk_arraycontains(py_arg(0), py_arg(1));
 | 
			
		||||
}
 | 
			
		||||
@ -409,33 +409,33 @@ py_Type pk_list__register() {
 | 
			
		||||
    py_Type type =
 | 
			
		||||
        pk_newtype("list", tp_object, NULL, (void (*)(void*))c11_vector__dtor, false, true);
 | 
			
		||||
 | 
			
		||||
    py_bindmagic(type, __len__, _py_list__len__);
 | 
			
		||||
    py_bindmagic(type, __eq__, _py_list__eq__);
 | 
			
		||||
    py_bindmagic(type, __ne__, _py_list__ne__);
 | 
			
		||||
    py_bindmagic(type, __new__, _py_list__new__);
 | 
			
		||||
    py_bindmagic(type, __getitem__, _py_list__getitem__);
 | 
			
		||||
    py_bindmagic(type, __setitem__, _py_list__setitem__);
 | 
			
		||||
    py_bindmagic(type, __delitem__, _py_list__delitem__);
 | 
			
		||||
    py_bindmagic(type, __add__, _py_list__add__);
 | 
			
		||||
    py_bindmagic(type, __mul__, _py_list__mul__);
 | 
			
		||||
    py_bindmagic(type, __rmul__, _py_list__rmul__);
 | 
			
		||||
    py_bindmagic(type, __repr__, _py_list__repr__);
 | 
			
		||||
    py_bindmagic(type, __iter__, _py_list__iter__);
 | 
			
		||||
    py_bindmagic(type, __contains__, _py_list__contains__);
 | 
			
		||||
    py_bindmagic(type, __len__, list__len__);
 | 
			
		||||
    py_bindmagic(type, __eq__, list__eq__);
 | 
			
		||||
    py_bindmagic(type, __ne__, list__ne__);
 | 
			
		||||
    py_bindmagic(type, __new__, list__new__);
 | 
			
		||||
    py_bindmagic(type, __getitem__, list__getitem__);
 | 
			
		||||
    py_bindmagic(type, __setitem__, list__setitem__);
 | 
			
		||||
    py_bindmagic(type, __delitem__, list__delitem__);
 | 
			
		||||
    py_bindmagic(type, __add__, list__add__);
 | 
			
		||||
    py_bindmagic(type, __mul__, list__mul__);
 | 
			
		||||
    py_bindmagic(type, __rmul__, list__rmul__);
 | 
			
		||||
    py_bindmagic(type, __repr__, list__repr__);
 | 
			
		||||
    py_bindmagic(type, __iter__, list__iter__);
 | 
			
		||||
    py_bindmagic(type, __contains__, list__contains__);
 | 
			
		||||
 | 
			
		||||
    py_bindmethod(type, "append", _py_list__append);
 | 
			
		||||
    py_bindmethod(type, "extend", _py_list__extend);
 | 
			
		||||
    py_bindmethod(type, "count", _py_list__count);
 | 
			
		||||
    py_bindmethod(type, "clear", _py_list__clear);
 | 
			
		||||
    py_bindmethod(type, "copy", _py_list__copy);
 | 
			
		||||
    py_bindmethod(type, "index", _py_list__index);
 | 
			
		||||
    py_bindmethod(type, "reverse", _py_list__reverse);
 | 
			
		||||
    py_bindmethod(type, "remove", _py_list__remove);
 | 
			
		||||
    py_bindmethod(type, "pop", _py_list__pop);
 | 
			
		||||
    py_bindmethod(type, "insert", _py_list__insert);
 | 
			
		||||
    py_bindmethod(type, "sort", _py_list__sort);
 | 
			
		||||
    py_bindmethod(type, "append", list__append);
 | 
			
		||||
    py_bindmethod(type, "extend", list__extend);
 | 
			
		||||
    py_bindmethod(type, "count", list__count);
 | 
			
		||||
    py_bindmethod(type, "clear", list__clear);
 | 
			
		||||
    py_bindmethod(type, "copy", list__copy);
 | 
			
		||||
    py_bindmethod(type, "index", list__index);
 | 
			
		||||
    py_bindmethod(type, "reverse", list__reverse);
 | 
			
		||||
    py_bindmethod(type, "remove", list__remove);
 | 
			
		||||
    py_bindmethod(type, "pop", list__pop);
 | 
			
		||||
    py_bindmethod(type, "insert", list__insert);
 | 
			
		||||
    py_bindmethod(type, "sort", list__sort);
 | 
			
		||||
 | 
			
		||||
    py_bind(py_tpobject(type), "sort(self, key=None, reverse=False)", _py_list__sort);
 | 
			
		||||
    py_bind(py_tpobject(type), "sort(self, key=None, reverse=False)", list__sort);
 | 
			
		||||
 | 
			
		||||
    py_setdict(py_tpobject(type), __hash__, py_None);
 | 
			
		||||
    return type;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										62
									
								
								src/public/py_method.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/public/py_method.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,62 @@
 | 
			
		||||
#include "pocketpy/pocketpy.h"
 | 
			
		||||
 | 
			
		||||
#include "pocketpy/common/utils.h"
 | 
			
		||||
#include "pocketpy/objects/object.h"
 | 
			
		||||
#include "pocketpy/interpreter/vm.h"
 | 
			
		||||
 | 
			
		||||
/* staticmethod */
 | 
			
		||||
 | 
			
		||||
static bool staticmethod__new__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    py_newobject(py_retval(), tp_staticmethod, 1, 0);
 | 
			
		||||
    py_setslot(py_retval(), 0, py_arg(1));
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
py_Type pk_staticmethod__register(){
 | 
			
		||||
    py_Type type = pk_newtype("staticmethod", tp_object, NULL, NULL, false, true);
 | 
			
		||||
    
 | 
			
		||||
    py_bindmagic(type, __new__, staticmethod__new__);
 | 
			
		||||
    return type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* classmethod */
 | 
			
		||||
static bool classmethod__new__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    py_newobject(py_retval(), tp_classmethod, 1, 0);
 | 
			
		||||
    py_setslot(py_retval(), 0, py_arg(1));
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
py_Type pk_classmethod__register(){
 | 
			
		||||
    py_Type type = pk_newtype("classmethod", tp_object, NULL, NULL, false, true);
 | 
			
		||||
 | 
			
		||||
    py_bindmagic(type, __new__, classmethod__new__);
 | 
			
		||||
    return type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* boundmethod */
 | 
			
		||||
static bool boundmethod__new__(int argc, py_Ref argv) {
 | 
			
		||||
    return NotImplementedError();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool boundmethod__self__getter(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    py_assign(py_retval(), py_getslot(argv, 0));
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool boundmethod__func__getter(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    py_assign(py_retval(), py_getslot(argv, 1));
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
py_Type pk_boundmethod__register(){
 | 
			
		||||
    py_Type type = pk_newtype("boundmethod", tp_object, NULL, NULL, false, true);
 | 
			
		||||
 | 
			
		||||
    py_bindmagic(type, __new__, boundmethod__new__);
 | 
			
		||||
    py_bindproperty(type, "__self__", boundmethod__self__getter, NULL);
 | 
			
		||||
    py_bindproperty(type, "__func__", boundmethod__func__getter, NULL);
 | 
			
		||||
    return type;
 | 
			
		||||
}
 | 
			
		||||
@ -2,10 +2,10 @@
 | 
			
		||||
#include "pocketpy/common/sstream.h"
 | 
			
		||||
#include "pocketpy/pocketpy.h"
 | 
			
		||||
 | 
			
		||||
static bool _py_object__new__(int argc, py_Ref argv) {
 | 
			
		||||
static bool object__new__(int argc, py_Ref argv) {
 | 
			
		||||
    if(argc == 0) return TypeError("object.__new__(): not enough arguments");
 | 
			
		||||
    py_Type cls = py_totype(py_arg(0));
 | 
			
		||||
    pk_TypeInfo* ti = c11__at(pk_TypeInfo, &pk_current_vm->types, cls);
 | 
			
		||||
    py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, cls);
 | 
			
		||||
    if(!ti->is_python) {
 | 
			
		||||
        return TypeError("object.__new__(%t) is not safe, use %t.__new__()", cls, cls);
 | 
			
		||||
    }
 | 
			
		||||
@ -13,28 +13,28 @@ static bool _py_object__new__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_object__hash__(int argc, py_Ref argv) {
 | 
			
		||||
static bool object__hash__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    assert(argv->is_ptr);
 | 
			
		||||
    py_newint(py_retval(), (py_i64)argv->_obj);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_object__eq__(int argc, py_Ref argv) {
 | 
			
		||||
static bool object__eq__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    bool res = py_isidentical(py_arg(0), py_arg(1));
 | 
			
		||||
    py_newbool(py_retval(), res);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_object__ne__(int argc, py_Ref argv) {
 | 
			
		||||
static bool object__ne__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    bool res = py_isidentical(py_arg(0), py_arg(1));
 | 
			
		||||
    py_newbool(py_retval(), !res);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_object__repr__(int argc, py_Ref argv) {
 | 
			
		||||
static bool object__repr__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    assert(argv->is_ptr);
 | 
			
		||||
    c11_sbuf buf;
 | 
			
		||||
@ -44,7 +44,7 @@ static bool _py_object__repr__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_type__repr__(int argc, py_Ref argv) {
 | 
			
		||||
static bool type__repr__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    c11_sbuf buf;
 | 
			
		||||
    c11_sbuf__ctor(&buf);
 | 
			
		||||
@ -53,23 +53,41 @@ static bool _py_type__repr__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_type__new__(int argc, py_Ref argv){
 | 
			
		||||
static bool type__new__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    py_Type type = py_typeof(py_arg(1));
 | 
			
		||||
    py_assign(py_retval(), py_tpobject(type));
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool type__base__getter(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    py_Type type = py_totype(argv);
 | 
			
		||||
    py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, type);
 | 
			
		||||
    py_assign(py_retval(), py_tpobject(ti->base));
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool type__name__getter(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    py_Type type = py_totype(argv);
 | 
			
		||||
    py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, type);
 | 
			
		||||
    py_newstr(py_retval(), py_name2str(ti->name));
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pk_object__register() {
 | 
			
		||||
    // use staticmethod
 | 
			
		||||
    py_bindmagic(tp_object, __new__, _py_object__new__);
 | 
			
		||||
    // TODO: use staticmethod
 | 
			
		||||
    py_bindmagic(tp_object, __new__, object__new__);
 | 
			
		||||
 | 
			
		||||
    py_bindmagic(tp_object, __hash__, _py_object__hash__);
 | 
			
		||||
    py_bindmagic(tp_object, __eq__, _py_object__eq__);
 | 
			
		||||
    py_bindmagic(tp_object, __ne__, _py_object__ne__);
 | 
			
		||||
    py_bindmagic(tp_object, __repr__, _py_object__repr__);
 | 
			
		||||
    py_bindmagic(tp_object, __hash__, object__hash__);
 | 
			
		||||
    py_bindmagic(tp_object, __eq__, object__eq__);
 | 
			
		||||
    py_bindmagic(tp_object, __ne__, object__ne__);
 | 
			
		||||
    py_bindmagic(tp_object, __repr__, object__repr__);
 | 
			
		||||
 | 
			
		||||
    // type patch...
 | 
			
		||||
    py_bindmagic(tp_type, __repr__, _py_type__repr__);
 | 
			
		||||
    py_bindmagic(tp_type, __new__, _py_type__new__);
 | 
			
		||||
    py_bindmagic(tp_type, __repr__, type__repr__);
 | 
			
		||||
    py_bindmagic(tp_type, __new__, type__new__);
 | 
			
		||||
 | 
			
		||||
    py_bindproperty(tp_type, "__base__", type__base__getter, NULL);
 | 
			
		||||
    py_bindproperty(tp_type, "__name__", type__name__getter, NULL);
 | 
			
		||||
}
 | 
			
		||||
@ -45,7 +45,7 @@ int py_bool(py_Ref val) {
 | 
			
		||||
 | 
			
		||||
bool py_hash(py_Ref val, int64_t* out) {
 | 
			
		||||
    py_Type t = val->type;
 | 
			
		||||
    pk_TypeInfo* types = (pk_TypeInfo*)pk_current_vm->types.data;
 | 
			
		||||
    py_TypeInfo* types = (py_TypeInfo*)pk_current_vm->types.data;
 | 
			
		||||
    do {
 | 
			
		||||
        py_Ref _hash = &types[t].magic[__hash__];
 | 
			
		||||
        if(py_isnone(_hash)) break;
 | 
			
		||||
@ -68,11 +68,16 @@ bool py_iter(py_Ref val) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int py_next(py_Ref val) {
 | 
			
		||||
    pk_VM* vm = pk_current_vm;
 | 
			
		||||
    VM* vm = pk_current_vm;
 | 
			
		||||
    vm->is_stopiteration = false;
 | 
			
		||||
    py_Ref tmp = py_tpfindmagic(val->type, __next__);
 | 
			
		||||
    if(!tmp) return TypeError("'%t' object is not an iterator", val->type);
 | 
			
		||||
    py_StackRef p0 = py_peek(0);
 | 
			
		||||
    if(py_call(tmp, 1, val)) return true;
 | 
			
		||||
    if(vm->curr_exception.type == tp_StopIteration) {
 | 
			
		||||
        py_clearexc(p0);
 | 
			
		||||
        vm->is_stopiteration = true;
 | 
			
		||||
    }
 | 
			
		||||
    return vm->is_stopiteration ? 0 : -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -108,8 +113,9 @@ bool py_getattr(py_Ref self, py_Name name) {
 | 
			
		||||
                if(py_istype(res, tp_staticmethod)) {
 | 
			
		||||
                    res = py_getslot(res, 0);
 | 
			
		||||
                } else if(py_istype(res, tp_classmethod)) {
 | 
			
		||||
                    // TODO: make a closure
 | 
			
		||||
                    assert(false);
 | 
			
		||||
                    res = py_getslot(res, 0);
 | 
			
		||||
                    py_newboundmethod(py_retval(), self, res);
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                py_assign(py_retval(), res);
 | 
			
		||||
                return true;
 | 
			
		||||
@ -120,10 +126,22 @@ bool py_getattr(py_Ref self, py_Name name) {
 | 
			
		||||
    if(cls_var) {
 | 
			
		||||
        // bound method is non-data descriptor
 | 
			
		||||
        switch(cls_var->type) {
 | 
			
		||||
            case tp_function: assert(false);
 | 
			
		||||
            case tp_nativefunc: assert(false);
 | 
			
		||||
            case tp_staticmethod: assert(false);
 | 
			
		||||
            case tp_classmethod: assert(false);
 | 
			
		||||
            case tp_function: {
 | 
			
		||||
                py_newboundmethod(py_retval(), self, cls_var);
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            case tp_nativefunc: {
 | 
			
		||||
                py_newboundmethod(py_retval(), self, cls_var);
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            case tp_staticmethod: {
 | 
			
		||||
                py_assign(py_retval(), py_getslot(cls_var, 0));
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            case tp_classmethod: {
 | 
			
		||||
                py_newboundmethod(py_retval(), py_tpobject(type), py_getslot(cls_var, 0));
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            default: {
 | 
			
		||||
                py_assign(py_retval(), cls_var);
 | 
			
		||||
                return true;
 | 
			
		||||
@ -131,6 +149,21 @@ bool py_getattr(py_Ref self, py_Name name) {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(self->type == tp_module) {
 | 
			
		||||
        py_Ref path = py_getdict(self, __path__);
 | 
			
		||||
        c11_sbuf buf;
 | 
			
		||||
        c11_sbuf__ctor(&buf);
 | 
			
		||||
        pk_sprintf(&buf, "%v.%n", py_tosv(path), name);
 | 
			
		||||
        c11_string* new_path = c11_sbuf__submit(&buf);
 | 
			
		||||
        int res = py_import(new_path->data);
 | 
			
		||||
        c11_string__delete(new_path);
 | 
			
		||||
        if(res == -1) {
 | 
			
		||||
            return false;
 | 
			
		||||
        } else if(res == 1) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return AttributeError(self, name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -200,12 +233,12 @@ bool py_delitem(py_Ref self, py_Ref key) {
 | 
			
		||||
    return ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int py_equal(py_Ref lhs, py_Ref rhs){
 | 
			
		||||
int py_equal(py_Ref lhs, py_Ref rhs) {
 | 
			
		||||
    if(!py_eq(lhs, rhs)) return -1;
 | 
			
		||||
    return py_bool(py_retval());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int py_less(py_Ref lhs, py_Ref rhs){
 | 
			
		||||
int py_less(py_Ref lhs, py_Ref rhs) {
 | 
			
		||||
    if(!py_lt(lhs, rhs)) return -1;
 | 
			
		||||
    return py_bool(py_retval());
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								src/public/py_property.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/public/py_property.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
			
		||||
#include "pocketpy/pocketpy.h"
 | 
			
		||||
 | 
			
		||||
#include "pocketpy/common/utils.h"
 | 
			
		||||
#include "pocketpy/objects/object.h"
 | 
			
		||||
#include "pocketpy/interpreter/vm.h"
 | 
			
		||||
 | 
			
		||||
static bool property__new__(int argc, py_Ref argv) {
 | 
			
		||||
    py_newobject(py_retval(), tp_property, 2, 0);
 | 
			
		||||
    if(argc == 1 + 1) {
 | 
			
		||||
        py_setslot(py_retval(), 0, py_arg(1));
 | 
			
		||||
        py_setslot(py_retval(), 1, py_None);
 | 
			
		||||
    } else if(argc == 1 + 2) {
 | 
			
		||||
        py_setslot(py_retval(), 0, py_arg(1));
 | 
			
		||||
        py_setslot(py_retval(), 1, py_arg(2));
 | 
			
		||||
    } else {
 | 
			
		||||
        return TypeError("property() expected 1 or 2 arguments, got %d", argc);
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
py_Type pk_property__register() {
 | 
			
		||||
    py_Type type = pk_newtype("property", tp_object, NULL, NULL, false, true);
 | 
			
		||||
 | 
			
		||||
    py_bindmagic(type, __new__, property__new__);
 | 
			
		||||
    return type;
 | 
			
		||||
}
 | 
			
		||||
@ -10,7 +10,7 @@ typedef struct Range {
 | 
			
		||||
    py_i64 step;
 | 
			
		||||
} Range;
 | 
			
		||||
 | 
			
		||||
static bool _py_range__new__(int argc, py_Ref argv) {
 | 
			
		||||
static bool range__new__(int argc, py_Ref argv) {
 | 
			
		||||
    Range* ud = py_newobject(py_retval(), tp_range, 0, sizeof(Range));
 | 
			
		||||
    switch(argc - 1) {  // skip cls
 | 
			
		||||
        case 1: {
 | 
			
		||||
@ -41,7 +41,7 @@ static bool _py_range__new__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_range__iter__(int argc, py_Ref argv) {
 | 
			
		||||
static bool range__iter__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    return py_tpcall(tp_range_iterator, 1, argv);
 | 
			
		||||
}
 | 
			
		||||
@ -49,8 +49,8 @@ static bool _py_range__iter__(int argc, py_Ref argv) {
 | 
			
		||||
py_Type pk_range__register() {
 | 
			
		||||
    py_Type type = pk_newtype("range", tp_object, NULL, NULL, false, true);
 | 
			
		||||
 | 
			
		||||
    py_bindmagic(type, __new__, _py_range__new__);
 | 
			
		||||
    py_bindmagic(type, __iter__, _py_range__iter__);
 | 
			
		||||
    py_bindmagic(type, __new__, range__new__);
 | 
			
		||||
    py_bindmagic(type, __iter__, range__iter__);
 | 
			
		||||
    return type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -59,7 +59,7 @@ typedef struct RangeIterator {
 | 
			
		||||
    py_i64 current;
 | 
			
		||||
} RangeIterator;
 | 
			
		||||
 | 
			
		||||
static bool _py_range_iterator__new__(int argc, py_Ref argv) {
 | 
			
		||||
static bool range_iterator__new__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    PY_CHECK_ARG_TYPE(1, tp_range);
 | 
			
		||||
    RangeIterator* ud = py_newobject(py_retval(), tp_range_iterator, 0, sizeof(RangeIterator));
 | 
			
		||||
@ -68,13 +68,13 @@ static bool _py_range_iterator__new__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_range_iterator__iter__(int argc, py_Ref argv) {
 | 
			
		||||
static bool range_iterator__iter__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    *py_retval() = *py_arg(0);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_range_iterator__next__(int argc, py_Ref argv) {
 | 
			
		||||
static bool range_iterator__next__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    RangeIterator* ud = py_touserdata(py_arg(0));
 | 
			
		||||
    if(ud->range.step > 0) {
 | 
			
		||||
@ -90,8 +90,8 @@ static bool _py_range_iterator__next__(int argc, py_Ref argv) {
 | 
			
		||||
py_Type pk_range_iterator__register() {
 | 
			
		||||
    py_Type type = pk_newtype("range_iterator", tp_object, NULL, NULL, false, true);
 | 
			
		||||
 | 
			
		||||
    py_bindmagic(type, __new__, _py_range_iterator__new__);
 | 
			
		||||
    py_bindmagic(type, __iter__, _py_range_iterator__iter__);
 | 
			
		||||
    py_bindmagic(type, __next__, _py_range_iterator__next__);
 | 
			
		||||
    py_bindmagic(type, __new__, range_iterator__new__);
 | 
			
		||||
    py_bindmagic(type, __iter__, range_iterator__iter__);
 | 
			
		||||
    py_bindmagic(type, __next__, range_iterator__next__);
 | 
			
		||||
    return type;
 | 
			
		||||
}
 | 
			
		||||
@ -6,14 +6,14 @@
 | 
			
		||||
#include "pocketpy/interpreter/vm.h"
 | 
			
		||||
 | 
			
		||||
void py_newslice(py_Ref out) {
 | 
			
		||||
    pk_VM* vm = pk_current_vm;
 | 
			
		||||
    PyObject* obj = pk_ManagedHeap__gcnew(&vm->heap, tp_slice, 3, 0);
 | 
			
		||||
    VM* vm = pk_current_vm;
 | 
			
		||||
    PyObject* obj = ManagedHeap__gcnew(&vm->heap, tp_slice, 3, 0);
 | 
			
		||||
    out->type = tp_slice;
 | 
			
		||||
    out->is_ptr = true;
 | 
			
		||||
    out->_obj = obj;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_slice__new__(int argc, py_Ref argv) {
 | 
			
		||||
static bool slice__new__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1 + 3);
 | 
			
		||||
    py_Ref slice = py_retval();
 | 
			
		||||
    py_newslice(slice);
 | 
			
		||||
@ -23,7 +23,7 @@ static bool _py_slice__new__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_slice__repr__(int argc, py_Ref argv) {
 | 
			
		||||
static bool slice__repr__(int argc, py_Ref argv) {
 | 
			
		||||
    c11_sbuf buf;
 | 
			
		||||
    c11_sbuf__ctor(&buf);
 | 
			
		||||
    c11_sbuf__write_cstr(&buf, "slice(");
 | 
			
		||||
@ -45,7 +45,7 @@ static bool _py_slice__repr__(int argc, py_Ref argv) {
 | 
			
		||||
py_Type pk_slice__register() {
 | 
			
		||||
    py_Type type = pk_newtype("slice", tp_object, NULL, NULL, false, true);
 | 
			
		||||
 | 
			
		||||
    py_bindmagic(type, __new__, _py_slice__new__);
 | 
			
		||||
    py_bindmagic(type, __repr__, _py_slice__repr__);
 | 
			
		||||
    py_bindmagic(type, __new__, slice__new__);
 | 
			
		||||
    py_bindmagic(type, __repr__, slice__repr__);
 | 
			
		||||
    return type;
 | 
			
		||||
}
 | 
			
		||||
@ -9,9 +9,9 @@
 | 
			
		||||
void py_newstr(py_Ref out, const char* data) { py_newstrn(out, data, strlen(data)); }
 | 
			
		||||
 | 
			
		||||
void py_newstrn(py_Ref out, const char* data, int size) {
 | 
			
		||||
    pk_ManagedHeap* heap = &pk_current_vm->heap;
 | 
			
		||||
    ManagedHeap* heap = &pk_current_vm->heap;
 | 
			
		||||
    int total_size = sizeof(c11_string) + size + 1;
 | 
			
		||||
    PyObject* obj = pk_ManagedHeap__gcnew(heap, tp_str, 0, total_size);
 | 
			
		||||
    PyObject* obj = ManagedHeap__gcnew(heap, tp_str, 0, total_size);
 | 
			
		||||
    c11_string* ud = PyObject__userdata(obj);
 | 
			
		||||
    c11_string__ctor2(ud, data, size);
 | 
			
		||||
    out->type = tp_str;
 | 
			
		||||
@ -20,9 +20,9 @@ void py_newstrn(py_Ref out, const char* data, int size) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned char* py_newbytes(py_Ref out, int size) {
 | 
			
		||||
    pk_ManagedHeap* heap = &pk_current_vm->heap;
 | 
			
		||||
    ManagedHeap* heap = &pk_current_vm->heap;
 | 
			
		||||
    // 4 bytes size + data
 | 
			
		||||
    PyObject* obj = pk_ManagedHeap__gcnew(heap, tp_bytes, 0, sizeof(c11_bytes) + size);
 | 
			
		||||
    PyObject* obj = ManagedHeap__gcnew(heap, tp_bytes, 0, sizeof(c11_bytes) + size);
 | 
			
		||||
    c11_bytes* ud = PyObject__userdata(obj);
 | 
			
		||||
    ud->size = size;
 | 
			
		||||
    out->type = tp_bytes;
 | 
			
		||||
@ -58,7 +58,7 @@ unsigned char* py_tobytes(py_Ref self, int* size) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////
 | 
			
		||||
static bool _py_str__new__(int argc, py_Ref argv) {
 | 
			
		||||
static bool str__new__(int argc, py_Ref argv) {
 | 
			
		||||
    assert(argc >= 1);
 | 
			
		||||
    if(argc == 1) {
 | 
			
		||||
        py_newstr(py_retval(), "");
 | 
			
		||||
@ -68,7 +68,7 @@ static bool _py_str__new__(int argc, py_Ref argv) {
 | 
			
		||||
    return py_str(py_arg(1));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__hash__(int argc, py_Ref argv) {
 | 
			
		||||
static bool str__hash__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    int size;
 | 
			
		||||
    const char* data = py_tostrn(&argv[0], &size);
 | 
			
		||||
@ -80,14 +80,14 @@ static bool _py_str__hash__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__len__(int argc, py_Ref argv) {
 | 
			
		||||
static bool str__len__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    c11_string* self = py_touserdata(&argv[0]);
 | 
			
		||||
    py_newint(py_retval(), c11_sv__u8_length((c11_sv){self->data, self->size}));
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__add__(int argc, py_Ref argv) {
 | 
			
		||||
static bool str__add__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    c11_string* self = py_touserdata(&argv[0]);
 | 
			
		||||
    if(py_arg(1)->type != tp_str) {
 | 
			
		||||
@ -105,7 +105,7 @@ static bool _py_str__add__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__mul__(int argc, py_Ref argv) {
 | 
			
		||||
static bool str__mul__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    c11_string* self = py_touserdata(&argv[0]);
 | 
			
		||||
    if(py_arg(1)->type != tp_int) {
 | 
			
		||||
@ -128,9 +128,9 @@ static bool _py_str__mul__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__rmul__(int argc, py_Ref argv) { return _py_str__mul__(argc, argv); }
 | 
			
		||||
static bool str__rmul__(int argc, py_Ref argv) { return str__mul__(argc, argv); }
 | 
			
		||||
 | 
			
		||||
static bool _py_str__contains__(int argc, py_Ref argv) {
 | 
			
		||||
static bool str__contains__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    c11_string* self = py_touserdata(&argv[0]);
 | 
			
		||||
    if(py_arg(1)->type != tp_str) {
 | 
			
		||||
@ -143,13 +143,13 @@ static bool _py_str__contains__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__str__(int argc, py_Ref argv) {
 | 
			
		||||
static bool str__str__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    *py_retval() = argv[0];
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__repr__(int argc, py_Ref argv) {
 | 
			
		||||
static bool str__repr__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    c11_sbuf buf;
 | 
			
		||||
    c11_sbuf__ctor(&buf);
 | 
			
		||||
@ -158,7 +158,7 @@ static bool _py_str__repr__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__iter__(int argc, py_Ref argv) {
 | 
			
		||||
static bool str__iter__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    int* ud = py_newobject(py_retval(), tp_str_iterator, 1, sizeof(int));
 | 
			
		||||
    *ud = 0;
 | 
			
		||||
@ -166,7 +166,7 @@ static bool _py_str__iter__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__getitem__(int argc, py_Ref argv) {
 | 
			
		||||
static bool str__getitem__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    c11_sv self = c11_string__sv(py_touserdata(&argv[0]));
 | 
			
		||||
    py_Ref _1 = py_arg(1);
 | 
			
		||||
@ -190,7 +190,7 @@ static bool _py_str__getitem__(int argc, py_Ref argv) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define DEF_STR_CMP_OP(op, __f, __cond)                                                            \
 | 
			
		||||
    static bool _py_str##op(int argc, py_Ref argv) {                                               \
 | 
			
		||||
    static bool str##op(int argc, py_Ref argv) {                                               \
 | 
			
		||||
        PY_CHECK_ARGC(2);                                                                          \
 | 
			
		||||
        c11_string* self = py_touserdata(&argv[0]);                                                \
 | 
			
		||||
        if(py_arg(1)->type != tp_str) {                                                            \
 | 
			
		||||
@ -212,7 +212,7 @@ DEF_STR_CMP_OP(__ge__, c11_sv__cmp, res >= 0)
 | 
			
		||||
 | 
			
		||||
#undef DEF_STR_CMP_OP
 | 
			
		||||
 | 
			
		||||
static bool _py_str__lower(int argc, py_Ref argv) {
 | 
			
		||||
static bool str__lower(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    c11_string* self = py_touserdata(&argv[0]);
 | 
			
		||||
    int total_size = sizeof(c11_string) + self->size + 1;
 | 
			
		||||
@ -227,7 +227,7 @@ static bool _py_str__lower(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__upper(int argc, py_Ref argv) {
 | 
			
		||||
static bool str__upper(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    c11_string* self = py_touserdata(&argv[0]);
 | 
			
		||||
    int total_size = sizeof(c11_string) + self->size + 1;
 | 
			
		||||
@ -242,29 +242,25 @@ static bool _py_str__upper(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__startswith(int argc, py_Ref argv) {
 | 
			
		||||
static bool str__startswith(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    c11_string* self = py_touserdata(&argv[0]);
 | 
			
		||||
    PY_CHECK_ARG_TYPE(1, tp_str);
 | 
			
		||||
    c11_string* other = py_touserdata(&argv[1]);
 | 
			
		||||
    c11_sv _0 = c11_sv__slice2(c11_string__sv(self), 0, other->size);
 | 
			
		||||
    c11_sv _1 = c11_string__sv(other);
 | 
			
		||||
    py_newbool(py_retval(), c11__sveq(_0, _1));
 | 
			
		||||
    py_newbool(py_retval(), c11_sv__startswith(c11_string__sv(self), c11_string__sv(other)));
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__endswith(int argc, py_Ref argv) {
 | 
			
		||||
static bool str__endswith(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    c11_string* self = py_touserdata(&argv[0]);
 | 
			
		||||
    PY_CHECK_ARG_TYPE(1, tp_str);
 | 
			
		||||
    c11_string* other = py_touserdata(&argv[1]);
 | 
			
		||||
    c11_sv _0 = c11_sv__slice2(c11_string__sv(self), self->size - other->size, self->size);
 | 
			
		||||
    c11_sv _1 = c11_string__sv(other);
 | 
			
		||||
    py_newbool(py_retval(), c11__sveq(_0, _1));
 | 
			
		||||
    py_newbool(py_retval(), c11_sv__endswith(c11_string__sv(self), c11_string__sv(other)));
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__join(int argc, py_Ref argv) {
 | 
			
		||||
static bool str__join(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    c11_sv self = c11_string__sv(py_touserdata(&argv[0]));
 | 
			
		||||
    py_Ref _1 = py_arg(1);
 | 
			
		||||
@ -296,7 +292,7 @@ static bool _py_str__join(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__replace(int argc, py_Ref argv) {
 | 
			
		||||
static bool str__replace(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(3);
 | 
			
		||||
    c11_string* self = py_touserdata(&argv[0]);
 | 
			
		||||
    PY_CHECK_ARG_TYPE(1, tp_str);
 | 
			
		||||
@ -310,7 +306,7 @@ static bool _py_str__replace(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__split(int argc, py_Ref argv) {
 | 
			
		||||
static bool str__split(int argc, py_Ref argv) {
 | 
			
		||||
    c11_sv self = c11_string__sv(py_touserdata(&argv[0]));
 | 
			
		||||
    c11_vector res;
 | 
			
		||||
    if(argc > 2) return TypeError("split() takes at most 2 arguments");
 | 
			
		||||
@ -333,7 +329,7 @@ static bool _py_str__split(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__count(int argc, py_Ref argv) {
 | 
			
		||||
static bool str__count(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    c11_string* self = py_touserdata(&argv[0]);
 | 
			
		||||
    PY_CHECK_ARG_TYPE(1, tp_str);
 | 
			
		||||
@ -343,7 +339,7 @@ static bool _py_str__count(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__strip_impl(bool left, bool right, int argc, py_Ref argv) {
 | 
			
		||||
static bool str__strip_impl(bool left, bool right, int argc, py_Ref argv) {
 | 
			
		||||
    c11_sv self = c11_string__sv(py_touserdata(&argv[0]));
 | 
			
		||||
    c11_sv chars;
 | 
			
		||||
    if(argc == 1) {
 | 
			
		||||
@ -359,19 +355,19 @@ static bool _py_str__strip_impl(bool left, bool right, int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__strip(int argc, py_Ref argv) {
 | 
			
		||||
    return _py_str__strip_impl(true, true, argc, argv);
 | 
			
		||||
static bool str__strip(int argc, py_Ref argv) {
 | 
			
		||||
    return str__strip_impl(true, true, argc, argv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__lstrip(int argc, py_Ref argv) {
 | 
			
		||||
    return _py_str__strip_impl(true, false, argc, argv);
 | 
			
		||||
static bool str__lstrip(int argc, py_Ref argv) {
 | 
			
		||||
    return str__strip_impl(true, false, argc, argv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__rstrip(int argc, py_Ref argv) {
 | 
			
		||||
    return _py_str__strip_impl(false, true, argc, argv);
 | 
			
		||||
static bool str__rstrip(int argc, py_Ref argv) {
 | 
			
		||||
    return str__strip_impl(false, true, argc, argv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__zfill(int argc, py_Ref argv) {
 | 
			
		||||
static bool str__zfill(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    c11_sv self = c11_string__sv(py_touserdata(&argv[0]));
 | 
			
		||||
    PY_CHECK_ARG_TYPE(1, tp_int);
 | 
			
		||||
@ -391,7 +387,7 @@ static bool _py_str__zfill(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__widthjust_impl(bool left, int argc, py_Ref argv) {
 | 
			
		||||
static bool str__widthjust_impl(bool left, int argc, py_Ref argv) {
 | 
			
		||||
    if(argc > 1 + 2) return TypeError("expected at most 2 arguments");
 | 
			
		||||
    char pad;
 | 
			
		||||
    if(argc == 1 + 1) {
 | 
			
		||||
@ -427,15 +423,15 @@ static bool _py_str__widthjust_impl(bool left, int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__ljust(int argc, py_Ref argv) {
 | 
			
		||||
    return _py_str__widthjust_impl(true, argc, argv);
 | 
			
		||||
static bool str__ljust(int argc, py_Ref argv) {
 | 
			
		||||
    return str__widthjust_impl(true, argc, argv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__rjust(int argc, py_Ref argv) {
 | 
			
		||||
    return _py_str__widthjust_impl(false, argc, argv);
 | 
			
		||||
static bool str__rjust(int argc, py_Ref argv) {
 | 
			
		||||
    return str__widthjust_impl(false, argc, argv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__find(int argc, py_Ref argv) {
 | 
			
		||||
static bool str__find(int argc, py_Ref argv) {
 | 
			
		||||
    if(argc > 3) return TypeError("find() takes at most 3 arguments");
 | 
			
		||||
    int start = 0;
 | 
			
		||||
    if(argc == 3) {
 | 
			
		||||
@ -450,8 +446,8 @@ static bool _py_str__find(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str__index(int argc, py_Ref argv) {
 | 
			
		||||
    bool ok = _py_str__find(argc, argv);
 | 
			
		||||
static bool str__index(int argc, py_Ref argv) {
 | 
			
		||||
    bool ok = str__find(argc, argv);
 | 
			
		||||
    if(!ok) return false;
 | 
			
		||||
    if(py_toint(py_retval()) == -1) return ValueError("substring not found");
 | 
			
		||||
    return true;
 | 
			
		||||
@ -461,51 +457,51 @@ py_Type pk_str__register() {
 | 
			
		||||
    py_Type type = pk_newtype("str", tp_object, NULL, NULL, false, true);
 | 
			
		||||
    // no need to dtor because the memory is controlled by the object
 | 
			
		||||
 | 
			
		||||
    py_bindmagic(tp_str, __new__, _py_str__new__);
 | 
			
		||||
    py_bindmagic(tp_str, __hash__, _py_str__hash__);
 | 
			
		||||
    py_bindmagic(tp_str, __len__, _py_str__len__);
 | 
			
		||||
    py_bindmagic(tp_str, __add__, _py_str__add__);
 | 
			
		||||
    py_bindmagic(tp_str, __mul__, _py_str__mul__);
 | 
			
		||||
    py_bindmagic(tp_str, __rmul__, _py_str__rmul__);
 | 
			
		||||
    py_bindmagic(tp_str, __contains__, _py_str__contains__);
 | 
			
		||||
    py_bindmagic(tp_str, __str__, _py_str__str__);
 | 
			
		||||
    py_bindmagic(tp_str, __repr__, _py_str__repr__);
 | 
			
		||||
    py_bindmagic(tp_str, __iter__, _py_str__iter__);
 | 
			
		||||
    py_bindmagic(tp_str, __getitem__, _py_str__getitem__);
 | 
			
		||||
    py_bindmagic(tp_str, __new__, str__new__);
 | 
			
		||||
    py_bindmagic(tp_str, __hash__, str__hash__);
 | 
			
		||||
    py_bindmagic(tp_str, __len__, str__len__);
 | 
			
		||||
    py_bindmagic(tp_str, __add__, str__add__);
 | 
			
		||||
    py_bindmagic(tp_str, __mul__, str__mul__);
 | 
			
		||||
    py_bindmagic(tp_str, __rmul__, str__rmul__);
 | 
			
		||||
    py_bindmagic(tp_str, __contains__, str__contains__);
 | 
			
		||||
    py_bindmagic(tp_str, __str__, str__str__);
 | 
			
		||||
    py_bindmagic(tp_str, __repr__, str__repr__);
 | 
			
		||||
    py_bindmagic(tp_str, __iter__, str__iter__);
 | 
			
		||||
    py_bindmagic(tp_str, __getitem__, str__getitem__);
 | 
			
		||||
 | 
			
		||||
    py_bindmagic(tp_str, __eq__, _py_str__eq__);
 | 
			
		||||
    py_bindmagic(tp_str, __ne__, _py_str__ne__);
 | 
			
		||||
    py_bindmagic(tp_str, __lt__, _py_str__lt__);
 | 
			
		||||
    py_bindmagic(tp_str, __le__, _py_str__le__);
 | 
			
		||||
    py_bindmagic(tp_str, __gt__, _py_str__gt__);
 | 
			
		||||
    py_bindmagic(tp_str, __ge__, _py_str__ge__);
 | 
			
		||||
    py_bindmagic(tp_str, __eq__, str__eq__);
 | 
			
		||||
    py_bindmagic(tp_str, __ne__, str__ne__);
 | 
			
		||||
    py_bindmagic(tp_str, __lt__, str__lt__);
 | 
			
		||||
    py_bindmagic(tp_str, __le__, str__le__);
 | 
			
		||||
    py_bindmagic(tp_str, __gt__, str__gt__);
 | 
			
		||||
    py_bindmagic(tp_str, __ge__, str__ge__);
 | 
			
		||||
 | 
			
		||||
    py_bindmethod(tp_str, "lower", _py_str__lower);
 | 
			
		||||
    py_bindmethod(tp_str, "upper", _py_str__upper);
 | 
			
		||||
    py_bindmethod(tp_str, "startswith", _py_str__startswith);
 | 
			
		||||
    py_bindmethod(tp_str, "endswith", _py_str__endswith);
 | 
			
		||||
    py_bindmethod(tp_str, "join", _py_str__join);
 | 
			
		||||
    py_bindmethod(tp_str, "replace", _py_str__replace);
 | 
			
		||||
    py_bindmethod(tp_str, "split", _py_str__split);
 | 
			
		||||
    py_bindmethod(tp_str, "count", _py_str__count);
 | 
			
		||||
    py_bindmethod(tp_str, "strip", _py_str__strip);
 | 
			
		||||
    py_bindmethod(tp_str, "lstrip", _py_str__lstrip);
 | 
			
		||||
    py_bindmethod(tp_str, "rstrip", _py_str__rstrip);
 | 
			
		||||
    py_bindmethod(tp_str, "zfill", _py_str__zfill);
 | 
			
		||||
    py_bindmethod(tp_str, "ljust", _py_str__ljust);
 | 
			
		||||
    py_bindmethod(tp_str, "rjust", _py_str__rjust);
 | 
			
		||||
    py_bindmethod(tp_str, "find", _py_str__find);
 | 
			
		||||
    py_bindmethod(tp_str, "index", _py_str__index);
 | 
			
		||||
    py_bindmethod(tp_str, "lower", str__lower);
 | 
			
		||||
    py_bindmethod(tp_str, "upper", str__upper);
 | 
			
		||||
    py_bindmethod(tp_str, "startswith", str__startswith);
 | 
			
		||||
    py_bindmethod(tp_str, "endswith", str__endswith);
 | 
			
		||||
    py_bindmethod(tp_str, "join", str__join);
 | 
			
		||||
    py_bindmethod(tp_str, "replace", str__replace);
 | 
			
		||||
    py_bindmethod(tp_str, "split", str__split);
 | 
			
		||||
    py_bindmethod(tp_str, "count", str__count);
 | 
			
		||||
    py_bindmethod(tp_str, "strip", str__strip);
 | 
			
		||||
    py_bindmethod(tp_str, "lstrip", str__lstrip);
 | 
			
		||||
    py_bindmethod(tp_str, "rstrip", str__rstrip);
 | 
			
		||||
    py_bindmethod(tp_str, "zfill", str__zfill);
 | 
			
		||||
    py_bindmethod(tp_str, "ljust", str__ljust);
 | 
			
		||||
    py_bindmethod(tp_str, "rjust", str__rjust);
 | 
			
		||||
    py_bindmethod(tp_str, "find", str__find);
 | 
			
		||||
    py_bindmethod(tp_str, "index", str__index);
 | 
			
		||||
    return type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str_iterator__iter__(int argc, py_Ref argv) {
 | 
			
		||||
static bool str_iterator__iter__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    *py_retval() = argv[0];
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_str_iterator__next__(int argc, py_Ref argv) {
 | 
			
		||||
static bool str_iterator__next__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    int* ud = py_touserdata(&argv[0]);
 | 
			
		||||
    int size;
 | 
			
		||||
@ -521,8 +517,8 @@ static bool _py_str_iterator__next__(int argc, py_Ref argv) {
 | 
			
		||||
py_Type pk_str_iterator__register() {
 | 
			
		||||
    py_Type type = pk_newtype("str_iterator", tp_object, NULL, NULL, false, true);
 | 
			
		||||
 | 
			
		||||
    py_bindmagic(type, __iter__, _py_str_iterator__iter__);
 | 
			
		||||
    py_bindmagic(type, __next__, _py_str_iterator__next__);
 | 
			
		||||
    py_bindmagic(type, __iter__, str_iterator__iter__);
 | 
			
		||||
    py_bindmagic(type, __next__, str_iterator__next__);
 | 
			
		||||
    return type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -538,10 +534,6 @@ bool py_str(py_Ref val) {
 | 
			
		||||
    return py_call(tmp, 1, val);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool py_repr(py_Ref val) {
 | 
			
		||||
    return pk_callmagic(__repr__, 1, val);
 | 
			
		||||
}
 | 
			
		||||
bool py_repr(py_Ref val) { return pk_callmagic(__repr__, 1, val); }
 | 
			
		||||
 | 
			
		||||
bool py_len(py_Ref val){
 | 
			
		||||
    return pk_callmagic(__len__, 1, val);
 | 
			
		||||
}
 | 
			
		||||
bool py_len(py_Ref val) { return pk_callmagic(__len__, 1, val); }
 | 
			
		||||
@ -6,8 +6,8 @@
 | 
			
		||||
#include "pocketpy/interpreter/vm.h"
 | 
			
		||||
 | 
			
		||||
void py_newtuple(py_Ref out, int n) {
 | 
			
		||||
    pk_VM* vm = pk_current_vm;
 | 
			
		||||
    PyObject* obj = pk_ManagedHeap__gcnew(&vm->heap, tp_tuple, n, 0);
 | 
			
		||||
    VM* vm = pk_current_vm;
 | 
			
		||||
    PyObject* obj = ManagedHeap__gcnew(&vm->heap, tp_tuple, n, 0);
 | 
			
		||||
    out->type = tp_tuple;
 | 
			
		||||
    out->is_ptr = true;
 | 
			
		||||
    out->_obj = obj;
 | 
			
		||||
@ -22,12 +22,12 @@ void py_tuple__setitem(py_Ref self, int i, py_Ref val) { py_setslot(self, i, val
 | 
			
		||||
int py_tuple__len(py_Ref self) { return self->_obj->slots; }
 | 
			
		||||
 | 
			
		||||
//////////////
 | 
			
		||||
static bool _py_tuple__len__(int argc, py_Ref argv) {
 | 
			
		||||
static bool tuple__len__(int argc, py_Ref argv) {
 | 
			
		||||
    py_newint(py_retval(), py_tuple__len(argv));
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_tuple__repr__(int argc, py_Ref argv) {
 | 
			
		||||
static bool tuple__repr__(int argc, py_Ref argv) {
 | 
			
		||||
    c11_sbuf buf;
 | 
			
		||||
    c11_sbuf__ctor(&buf);
 | 
			
		||||
    c11_sbuf__write_char(&buf, '(');
 | 
			
		||||
@ -48,7 +48,7 @@ static bool _py_tuple__repr__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_tuple__new__(int argc, py_Ref argv) {
 | 
			
		||||
static bool tuple__new__(int argc, py_Ref argv) {
 | 
			
		||||
    if(argc == 1 + 0) {
 | 
			
		||||
        py_newtuple(py_retval(), 0);
 | 
			
		||||
        return true;
 | 
			
		||||
@ -69,7 +69,7 @@ static bool _py_tuple__new__(int argc, py_Ref argv) {
 | 
			
		||||
    return TypeError("tuple() takes at most 1 argument");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_tuple__getitem__(int argc, py_Ref argv) {
 | 
			
		||||
static bool tuple__getitem__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    int length = py_tuple__len(argv);
 | 
			
		||||
    py_Ref _1 = py_arg(1);
 | 
			
		||||
@ -97,7 +97,7 @@ static bool _py_tuple__getitem__(int argc, py_Ref argv) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_tuple__eq__(int argc, py_Ref argv) {
 | 
			
		||||
static bool tuple__eq__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    if(py_istype(py_arg(1), tp_tuple)) {
 | 
			
		||||
        int length0, length1;
 | 
			
		||||
@ -112,8 +112,8 @@ static bool _py_tuple__eq__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_tuple__ne__(int argc, py_Ref argv) {
 | 
			
		||||
    if(!_py_tuple__eq__(argc, argv)) return false;
 | 
			
		||||
static bool tuple__ne__(int argc, py_Ref argv) {
 | 
			
		||||
    if(!tuple__eq__(argc, argv)) return false;
 | 
			
		||||
    if(py_isbool(py_retval())) {
 | 
			
		||||
        bool res = py_tobool(py_retval());
 | 
			
		||||
        py_newbool(py_retval(), !res);
 | 
			
		||||
@ -121,12 +121,12 @@ static bool _py_tuple__ne__(int argc, py_Ref argv) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_tuple__iter__(int argc, py_Ref argv) {
 | 
			
		||||
static bool tuple__iter__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(1);
 | 
			
		||||
    return pk_arrayiter(argv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool _py_tuple__contains__(int argc, py_Ref argv) {
 | 
			
		||||
static bool tuple__contains__(int argc, py_Ref argv) {
 | 
			
		||||
    PY_CHECK_ARGC(2);
 | 
			
		||||
    return pk_arraycontains(py_arg(0), py_arg(1));
 | 
			
		||||
}
 | 
			
		||||
@ -134,13 +134,13 @@ static bool _py_tuple__contains__(int argc, py_Ref argv) {
 | 
			
		||||
py_Type pk_tuple__register() {
 | 
			
		||||
    py_Type type = pk_newtype("tuple", tp_object, NULL, NULL, false, true);
 | 
			
		||||
 | 
			
		||||
    py_bindmagic(type, __len__, _py_tuple__len__);
 | 
			
		||||
    py_bindmagic(type, __repr__, _py_tuple__repr__);
 | 
			
		||||
    py_bindmagic(type, __new__, _py_tuple__new__);
 | 
			
		||||
    py_bindmagic(type, __getitem__, _py_tuple__getitem__);
 | 
			
		||||
    py_bindmagic(type, __eq__, _py_tuple__eq__);
 | 
			
		||||
    py_bindmagic(type, __ne__, _py_tuple__ne__);
 | 
			
		||||
    py_bindmagic(type, __iter__, _py_tuple__iter__);
 | 
			
		||||
    py_bindmagic(type, __contains__, _py_tuple__contains__);
 | 
			
		||||
    py_bindmagic(type, __len__, tuple__len__);
 | 
			
		||||
    py_bindmagic(type, __repr__, tuple__repr__);
 | 
			
		||||
    py_bindmagic(type, __new__, tuple__new__);
 | 
			
		||||
    py_bindmagic(type, __getitem__, tuple__getitem__);
 | 
			
		||||
    py_bindmagic(type, __eq__, tuple__eq__);
 | 
			
		||||
    py_bindmagic(type, __ne__, tuple__ne__);
 | 
			
		||||
    py_bindmagic(type, __iter__, tuple__iter__);
 | 
			
		||||
    py_bindmagic(type, __contains__, tuple__contains__);
 | 
			
		||||
    return type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,7 @@ void py_setreg(int i, py_Ref val) { pk_current_vm->reg[i] = *val; }
 | 
			
		||||
py_Ref py_getdict(py_Ref self, py_Name name) {
 | 
			
		||||
    assert(self && self->is_ptr);
 | 
			
		||||
    if(!py_ismagicname(name) || self->type != tp_type) {
 | 
			
		||||
        return pk_NameDict__try_get(PyObject__dict(self->_obj), name);
 | 
			
		||||
        return NameDict__try_get(PyObject__dict(self->_obj), name);
 | 
			
		||||
    } else {
 | 
			
		||||
        py_Type* ud = py_touserdata(self);
 | 
			
		||||
        py_Ref slot = py_tpmagic(*ud, name);
 | 
			
		||||
@ -22,17 +22,22 @@ py_Ref py_getdict(py_Ref self, py_Name name) {
 | 
			
		||||
void py_setdict(py_Ref self, py_Name name, py_Ref val) {
 | 
			
		||||
    assert(self && self->is_ptr);
 | 
			
		||||
    if(!py_ismagicname(name) || self->type != tp_type) {
 | 
			
		||||
        pk_NameDict__set(PyObject__dict(self->_obj), name, *val);
 | 
			
		||||
        NameDict__set(PyObject__dict(self->_obj), name, *val);
 | 
			
		||||
    } else {
 | 
			
		||||
        py_Type* ud = py_touserdata(self);
 | 
			
		||||
        *py_tpmagic(*ud, name) = *val;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
py_TmpRef py_emplacedict(py_Ref self, py_Name name){
 | 
			
		||||
    py_setdict(self, name, py_NIL);
 | 
			
		||||
    return py_getdict(self, name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool py_deldict(py_Ref self, py_Name name) {
 | 
			
		||||
    assert(self && self->is_ptr);
 | 
			
		||||
    if(!py_ismagicname(name) || self->type != tp_type) {
 | 
			
		||||
        return pk_NameDict__del(PyObject__dict(self->_obj), name);
 | 
			
		||||
        return NameDict__del(PyObject__dict(self->_obj), name);
 | 
			
		||||
 | 
			
		||||
    } else {
 | 
			
		||||
        py_Type* ud = py_touserdata(self);
 | 
			
		||||
@ -57,32 +62,32 @@ void py_assign(py_Ref dst, py_Ref src) { *dst = *src; }
 | 
			
		||||
 | 
			
		||||
/* Stack References */
 | 
			
		||||
py_Ref py_peek(int i) {
 | 
			
		||||
    assert(i < 0);
 | 
			
		||||
    assert(i <= 0);
 | 
			
		||||
    return pk_current_vm->stack.sp + i;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void py_pop() {
 | 
			
		||||
    pk_VM* vm = pk_current_vm;
 | 
			
		||||
    VM* vm = pk_current_vm;
 | 
			
		||||
    vm->stack.sp--;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void py_shrink(int n) {
 | 
			
		||||
    pk_VM* vm = pk_current_vm;
 | 
			
		||||
    VM* vm = pk_current_vm;
 | 
			
		||||
    vm->stack.sp -= n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void py_push(py_Ref src) {
 | 
			
		||||
    pk_VM* vm = pk_current_vm;
 | 
			
		||||
    VM* vm = pk_current_vm;
 | 
			
		||||
    *vm->stack.sp++ = *src;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void py_pushnil() {
 | 
			
		||||
    pk_VM* vm = pk_current_vm;
 | 
			
		||||
    VM* vm = pk_current_vm;
 | 
			
		||||
    py_newnil(vm->stack.sp++);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
py_Ref py_pushtmp() {
 | 
			
		||||
    pk_VM* vm = pk_current_vm;
 | 
			
		||||
    VM* vm = pk_current_vm;
 | 
			
		||||
    py_newnil(vm->stack.sp++);
 | 
			
		||||
    return py_peek(-1);
 | 
			
		||||
}
 | 
			
		||||
@ -60,22 +60,31 @@ void py_bindfunc(py_Ref obj, const char* name, py_CFunction f) {
 | 
			
		||||
    py_setdict(obj, py_name(name), &tmp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void py_bindproperty(py_Type type, const char* name, py_CFunction getter, py_CFunction setter) {
 | 
			
		||||
    py_TValue tmp;
 | 
			
		||||
    py_newobject(&tmp, tp_property, 2, 0);
 | 
			
		||||
    py_newnativefunc(py_getslot(&tmp, 0), getter);
 | 
			
		||||
    if(setter) {
 | 
			
		||||
        py_newnativefunc(py_getslot(&tmp, 1), setter);
 | 
			
		||||
    } else {
 | 
			
		||||
        py_setslot(&tmp, 1, py_None);
 | 
			
		||||
    }
 | 
			
		||||
    py_setdict(py_tpobject(type), py_name(name), &tmp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void py_bind(py_Ref obj, const char* sig, py_CFunction f) {
 | 
			
		||||
    py_TValue tmp;
 | 
			
		||||
    py_Name name = py_newfunction(&tmp, sig, f, NULL, 0);
 | 
			
		||||
    py_setdict(obj, name, &tmp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
py_Name py_newfunction(py_Ref out,
 | 
			
		||||
                       const char* sig,
 | 
			
		||||
                       py_CFunction f,
 | 
			
		||||
                       const char* docstring,
 | 
			
		||||
                       int slots) {
 | 
			
		||||
py_Name
 | 
			
		||||
    py_newfunction(py_Ref out, const char* sig, py_CFunction f, const char* docstring, int slots) {
 | 
			
		||||
    char buffer[256];
 | 
			
		||||
    snprintf(buffer, sizeof(buffer), "def %s: pass", sig);
 | 
			
		||||
    // fn(a, b, *c, d=1) -> None
 | 
			
		||||
    CodeObject code;
 | 
			
		||||
    pk_SourceData_ source = pk_SourceData__rcnew(buffer, "<bind>", EXEC_MODE, false);
 | 
			
		||||
    SourceData_ source = SourceData__rcnew(buffer, "<bind>", EXEC_MODE, false);
 | 
			
		||||
    Error* err = pk_compile(source, &code);
 | 
			
		||||
    if(err || code.func_decls.count != 1) {
 | 
			
		||||
        c11__abort("py_newfunction(): invalid signature '%s'", sig);
 | 
			
		||||
@ -92,9 +101,15 @@ py_Name py_newfunction(py_Ref out,
 | 
			
		||||
    return py_name(ud->decl->code.name->data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void py_newboundmethod(py_Ref out, py_Ref self, py_Ref func){
 | 
			
		||||
    py_newobject(out, tp_boundmethod, 2, 0);
 | 
			
		||||
    py_setslot(out, 0, self);
 | 
			
		||||
    py_setslot(out, 1, func);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* py_newobject(py_Ref out, py_Type type, int slots, int udsize) {
 | 
			
		||||
    pk_ManagedHeap* heap = &pk_current_vm->heap;
 | 
			
		||||
    PyObject* obj = pk_ManagedHeap__gcnew(heap, type, slots, udsize);
 | 
			
		||||
    ManagedHeap* heap = &pk_current_vm->heap;
 | 
			
		||||
    PyObject* obj = ManagedHeap__gcnew(heap, type, slots, udsize);
 | 
			
		||||
    out->type = type;
 | 
			
		||||
    out->is_ptr = true;
 | 
			
		||||
    out->_obj = obj;
 | 
			
		||||
 | 
			
		||||
@ -46,7 +46,7 @@ int main(int argc, char** argv) {
 | 
			
		||||
        printf("Type \"exit()\" to exit.\n");
 | 
			
		||||
 | 
			
		||||
        while(true) {
 | 
			
		||||
            int size = py_replinput(buf);
 | 
			
		||||
            int size = py_replinput(buf, sizeof(buf));
 | 
			
		||||
            assert(size < sizeof(buf));
 | 
			
		||||
            if(size >= 0) {
 | 
			
		||||
                if(!py_exec(buf, "<stdin>", REPL_MODE, NULL)) py_printexc();
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,7 @@ class Task:
 | 
			
		||||
 | 
			
		||||
    def __next__(self):
 | 
			
		||||
        if self.i == self.n:
 | 
			
		||||
            return StopIteration
 | 
			
		||||
            raise StopIteration
 | 
			
		||||
        self.i += 1
 | 
			
		||||
        return self.i
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ except ImportError:
 | 
			
		||||
    exit(0)
 | 
			
		||||
 | 
			
		||||
os.chdir('tests')
 | 
			
		||||
assert os.getcwd().endswith('tests')
 | 
			
		||||
 | 
			
		||||
import test1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,11 @@
 | 
			
		||||
class A:
 | 
			
		||||
    def __init__(self, a, b):
 | 
			
		||||
    def __init__(self, a, __b):
 | 
			
		||||
        self.a = a
 | 
			
		||||
        self.b = b
 | 
			
		||||
        self.__b = __b
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def b(self):
 | 
			
		||||
        return self.__b
 | 
			
		||||
 | 
			
		||||
    def add(self):
 | 
			
		||||
        return self.a + self.b
 | 
			
		||||
@ -110,14 +114,6 @@ class B(A):
 | 
			
		||||
assert B.b == 3
 | 
			
		||||
assert B.c == 4
 | 
			
		||||
 | 
			
		||||
import c
 | 
			
		||||
 | 
			
		||||
class A(c.void_p):
 | 
			
		||||
    pass
 | 
			
		||||
    
 | 
			
		||||
a = A(0)
 | 
			
		||||
assert repr(a).startswith('<void* at')
 | 
			
		||||
 | 
			
		||||
if 1:
 | 
			
		||||
    class TrueClass:
 | 
			
		||||
        pass
 | 
			
		||||
@ -1,8 +0,0 @@
 | 
			
		||||
def f(n):
 | 
			
		||||
    def g(x):
 | 
			
		||||
        if x==n:
 | 
			
		||||
            return n
 | 
			
		||||
        return g(x+1)
 | 
			
		||||
    return g(0)
 | 
			
		||||
 | 
			
		||||
assert f(10) == 10
 | 
			
		||||
@ -24,4 +24,14 @@ def f3(x, y):
 | 
			
		||||
    return lambda z: x + y + z
 | 
			
		||||
 | 
			
		||||
a = f3(1, 2)
 | 
			
		||||
assert a(3) == 6
 | 
			
		||||
assert a(3) == 6
 | 
			
		||||
 | 
			
		||||
# closure ex
 | 
			
		||||
def f(n):
 | 
			
		||||
    def g(x):
 | 
			
		||||
        if x==n:
 | 
			
		||||
            return n
 | 
			
		||||
        return g(x+1)
 | 
			
		||||
    return g(0)
 | 
			
		||||
 | 
			
		||||
assert f(10) == 10
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user