mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-27 06:50:18 +00:00
Compare commits
5 Commits
92fcc116af
...
28c3b35d39
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
28c3b35d39 | ||
|
|
58c5bb1d35 | ||
|
|
841be061e0 | ||
|
|
783bbfb4ba | ||
|
|
aea3b4758f |
@ -1,5 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "stdlib.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -88,6 +88,9 @@ void* c11_vector__emplace(c11_vector* self);
|
|||||||
} \
|
} \
|
||||||
}while(0)
|
}while(0)
|
||||||
|
|
||||||
|
#define c11_vector__foreach(T, self, it) \
|
||||||
|
for(T* it = (T*)(self)->data; it != (T*)(self)->data + (self)->count; it++)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -54,7 +54,7 @@ struct Compiler {
|
|||||||
CompileMode mode() const noexcept{ return lexer.src->mode; }
|
CompileMode mode() const noexcept{ return lexer.src->mode; }
|
||||||
|
|
||||||
NameScope name_scope() const noexcept;
|
NameScope name_scope() const noexcept;
|
||||||
CodeObject_ push_global_context() noexcept;
|
CodeObject* push_global_context() noexcept;
|
||||||
FuncDecl_ push_f_context(Str name) noexcept;
|
FuncDecl_ push_f_context(Str name) noexcept;
|
||||||
|
|
||||||
static void init_pratt_rules() noexcept;
|
static void init_pratt_rules() noexcept;
|
||||||
@ -134,7 +134,7 @@ struct Compiler {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Compiler(VM* vm, std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope = false) noexcept;
|
Compiler(VM* vm, std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope = false) noexcept;
|
||||||
[[nodiscard]] Error* compile(CodeObject_* out) noexcept;
|
[[nodiscard]] Error* compile(CodeObject** out) noexcept;
|
||||||
~Compiler();
|
~Compiler();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
52
include/pocketpy/compiler/expr.h
Normal file
52
include/pocketpy/compiler/expr.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// #pragma once
|
||||||
|
|
||||||
|
// #include <stdbool.h>
|
||||||
|
// #include "pocketpy/common/memorypool.h"
|
||||||
|
// #include "pocketpy/compiler/lexer.h"
|
||||||
|
|
||||||
|
// #ifdef __cplusplus
|
||||||
|
// extern "C" {
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// struct pk_Expr;
|
||||||
|
// struct pk_CodeEmitContext;
|
||||||
|
|
||||||
|
// struct pk_ExprVt{
|
||||||
|
// void (*dtor)(pk_Expr*);
|
||||||
|
// /* reflections */
|
||||||
|
// bool (*is_literal)(const pk_Expr*);
|
||||||
|
// bool (*is_json_object)(const pk_Expr*);
|
||||||
|
// bool (*is_attrib)(const pk_Expr*);
|
||||||
|
// bool (*is_subscr)(const pk_Expr*);
|
||||||
|
// bool (*is_compare)(const pk_Expr*);
|
||||||
|
// int (*star_level)(const pk_Expr*);
|
||||||
|
// bool (*is_tuple)(const pk_Expr*);
|
||||||
|
// bool (*is_name)(const pk_Expr*);
|
||||||
|
// /* emit */
|
||||||
|
// void (*emit_)(pk_Expr*, pk_CodeEmitContext*);
|
||||||
|
// bool (*emit_del)(pk_Expr*, pk_CodeEmitContext*);
|
||||||
|
// bool (*emit_store)(pk_Expr*, pk_CodeEmitContext*);
|
||||||
|
// void (*emit_inplace)(pk_Expr*, pk_CodeEmitContext*);
|
||||||
|
// bool (*emit_store_inplace)(pk_Expr*, pk_CodeEmitContext*);
|
||||||
|
// };
|
||||||
|
|
||||||
|
// typedef struct pk_Expr{
|
||||||
|
// pk_ExprVt* vt;
|
||||||
|
// int line;
|
||||||
|
// } pk_Expr;
|
||||||
|
|
||||||
|
// void pk_ExprVt__ctor(pk_ExprVt* vt);
|
||||||
|
// void pk_Expr__emit_(pk_Expr* self, pk_CodeEmitContext* ctx);
|
||||||
|
// bool pk_Expr__emit_del(pk_Expr* self, pk_CodeEmitContext* ctx);
|
||||||
|
// bool pk_Expr__emit_store(pk_Expr* self, pk_CodeEmitContext* ctx);
|
||||||
|
// void pk_Expr__emit_inplace(pk_Expr* self, pk_CodeEmitContext* ctx);
|
||||||
|
// bool pk_Expr__emit_store_inplace(pk_Expr* self, pk_CodeEmitContext* ctx);
|
||||||
|
// void pk_Expr__delete(pk_Expr* self);
|
||||||
|
|
||||||
|
// typedef struct pk_CodeEmitContext{
|
||||||
|
|
||||||
|
// } pk_CodeEmitContext;
|
||||||
|
|
||||||
|
// #ifdef __cplusplus
|
||||||
|
// }
|
||||||
|
// #endif
|
||||||
@ -10,48 +10,7 @@ struct Expr;
|
|||||||
|
|
||||||
typedef small_vector<Expr*, 4> Expr_vector;
|
typedef small_vector<Expr*, 4> Expr_vector;
|
||||||
|
|
||||||
static bool default_false(const Expr*) { return false; }
|
|
||||||
static int default_zero(const Expr*) { return 0; }
|
|
||||||
static void default_dtor(Expr*) {}
|
|
||||||
|
|
||||||
struct ExprVt{
|
|
||||||
void (*dtor)(Expr*);
|
|
||||||
/* reflections */
|
|
||||||
bool (*is_literal)(const Expr*);
|
|
||||||
bool (*is_json_object)(const Expr*);
|
|
||||||
bool (*is_attrib)(const Expr*);
|
|
||||||
bool (*is_subscr)(const Expr*);
|
|
||||||
bool (*is_compare)(const Expr*);
|
|
||||||
int (*star_level)(const Expr*);
|
|
||||||
bool (*is_tuple)(const Expr*);
|
|
||||||
bool (*is_name)(const Expr*);
|
|
||||||
/* emit */
|
|
||||||
void (*emit_)(Expr*, CodeEmitContext*);
|
|
||||||
bool (*emit_del)(Expr*, CodeEmitContext*);
|
|
||||||
bool (*emit_store)(Expr*, CodeEmitContext*);
|
|
||||||
void (*emit_inplace)(Expr*, CodeEmitContext*);
|
|
||||||
bool (*emit_store_inplace)(Expr*, CodeEmitContext*);
|
|
||||||
};
|
|
||||||
|
|
||||||
void ExprVt__ctor(ExprVt* vt){
|
|
||||||
vt->dtor = default_dtor;
|
|
||||||
vt->is_literal = default_false;
|
|
||||||
vt->is_json_object = default_false;
|
|
||||||
vt->is_attrib = default_false;
|
|
||||||
vt->is_subscr = default_false;
|
|
||||||
vt->is_compare = default_false;
|
|
||||||
vt->star_level = default_zero;
|
|
||||||
vt->is_tuple = default_false;
|
|
||||||
vt->is_name = default_false;
|
|
||||||
vt->emit_ = NULL; // must be set
|
|
||||||
vt->emit_del = NULL;
|
|
||||||
vt->emit_store = NULL;
|
|
||||||
vt->emit_inplace = NULL;
|
|
||||||
vt->emit_store_inplace = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Expr {
|
struct Expr {
|
||||||
ExprVt* vt;
|
|
||||||
int line = 0;
|
int line = 0;
|
||||||
virtual ~Expr() = default;
|
virtual ~Expr() = default;
|
||||||
virtual void emit_(CodeEmitContext* ctx) = 0;
|
virtual void emit_(CodeEmitContext* ctx) = 0;
|
||||||
@ -80,36 +39,6 @@ struct Expr {
|
|||||||
[[nodiscard]] virtual bool emit_store_inplace(CodeEmitContext* ctx) { return emit_store(ctx); }
|
[[nodiscard]] virtual bool emit_store_inplace(CodeEmitContext* ctx) { return emit_store(ctx); }
|
||||||
};
|
};
|
||||||
|
|
||||||
void pk_Expr__emit_(Expr* self, CodeEmitContext* ctx){
|
|
||||||
assert(self->vt->emit_);
|
|
||||||
self->vt->emit_(self, ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pk_Expr__emit_del(Expr* self, CodeEmitContext* ctx){
|
|
||||||
if(!self->vt->emit_del) return false;
|
|
||||||
return self->vt->emit_del(self, ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pk_Expr__emit_store(Expr* self, CodeEmitContext* ctx){
|
|
||||||
if(!self->vt->emit_store) return false;
|
|
||||||
return self->vt->emit_store(self, ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pk_Expr__emit_inplace(Expr* self, CodeEmitContext* ctx){
|
|
||||||
if(!self->vt->emit_inplace){
|
|
||||||
pk_Expr__emit_(self, ctx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self->vt->emit_inplace(self, ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pk_Expr__emit_store_inplace(Expr* self, CodeEmitContext* ctx){
|
|
||||||
if(!self->vt->emit_store_inplace){
|
|
||||||
return pk_Expr__emit_store(self, ctx);
|
|
||||||
}
|
|
||||||
return self->vt->emit_store_inplace(self, ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void delete_expr(Expr* p) noexcept{
|
inline void delete_expr(Expr* p) noexcept{
|
||||||
if(!p) return;
|
if(!p) return;
|
||||||
p->~Expr();
|
p->~Expr();
|
||||||
@ -119,12 +48,12 @@ inline void delete_expr(Expr* p) noexcept{
|
|||||||
struct CodeEmitContext{
|
struct CodeEmitContext{
|
||||||
VM* vm;
|
VM* vm;
|
||||||
FuncDecl_ func; // optional
|
FuncDecl_ func; // optional
|
||||||
CodeObject_ co; // 1 CodeEmitContext <=> 1 CodeObject_
|
CodeObject* co; // 1 CodeEmitContext <=> 1 CodeObject*
|
||||||
vector<Expr*> _s_expr;
|
vector<Expr*> _s_expr;
|
||||||
int level;
|
int level;
|
||||||
vector<StrName> global_names;
|
vector<StrName> global_names;
|
||||||
|
|
||||||
CodeEmitContext(VM* vm, CodeObject_ co, int level) : vm(vm), co(co), level(level) {
|
CodeEmitContext(VM* vm, CodeObject* co, int level) : vm(vm), co(co), level(level) {
|
||||||
c11_smallmap_s2n__ctor(&_co_consts_string_dedup_map);
|
c11_smallmap_s2n__ctor(&_co_consts_string_dedup_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -175,7 +175,7 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) {
|
|||||||
return obj; \
|
return obj; \
|
||||||
}, \
|
}, \
|
||||||
{}, \
|
{}, \
|
||||||
BindType::STATICMETHOD); \
|
BindType_STATICMETHOD); \
|
||||||
vm->bind_func(type, "tostruct", 1, [](VM* vm, ArgsView args) { \
|
vm->bind_func(type, "tostruct", 1, [](VM* vm, ArgsView args) { \
|
||||||
wT& self = _CAST(wT&, args[0]); \
|
wT& self = _CAST(wT&, args[0]); \
|
||||||
return vm->new_user_object<Struct>(&self, sizeof(wT)); \
|
return vm->new_user_object<Struct>(&self, sizeof(wT)); \
|
||||||
|
|||||||
@ -130,9 +130,9 @@ struct Frame {
|
|||||||
_uw_list(nullptr) {}
|
_uw_list(nullptr) {}
|
||||||
|
|
||||||
// global scope
|
// global scope
|
||||||
Frame(PyVar* p0, const CodeObject_& co, PyObject* _module) :
|
Frame(PyVar* p0, const CodeObject* co, PyObject* _module) :
|
||||||
_ip(co->codes.data() - 1), _sp_base(p0), co(co.get()), _module(_module), _callable(nullptr),
|
_ip(co->codes.data() - 1), _sp_base(p0), co(co), _module(_module), _callable(nullptr),
|
||||||
_locals(co.get(), p0), _uw_list(nullptr) {}
|
_locals(co, p0), _uw_list(nullptr) {}
|
||||||
|
|
||||||
PyVar* actual_sp_base() const { return _locals.a; }
|
PyVar* actual_sp_base() const { return _locals.a; }
|
||||||
|
|
||||||
@ -143,7 +143,7 @@ struct Frame {
|
|||||||
int _exit_block(ValueStack*, int);
|
int _exit_block(ValueStack*, int);
|
||||||
|
|
||||||
[[nodiscard]] int prepare_loop_break(ValueStack* s_data) {
|
[[nodiscard]] int prepare_loop_break(ValueStack* s_data) {
|
||||||
int target = co->_get_block_codei(ip()).end;
|
int target = co->blocks[co->lines[ip()].iblock].end;
|
||||||
prepare_jump_break(s_data, target);
|
prepare_jump_break(s_data, target);
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -265,7 +265,7 @@ public:
|
|||||||
ArgsView cast_array_view(PyVar obj);
|
ArgsView cast_array_view(PyVar obj);
|
||||||
void set_main_argv(int argc, char** argv);
|
void set_main_argv(int argc, char** argv);
|
||||||
i64 normalized_index(i64 index, int size);
|
i64 normalized_index(i64 index, int size);
|
||||||
Str disassemble(CodeObject_ co);
|
Str disassemble(CodeObject* co);
|
||||||
void parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step);
|
void parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step);
|
||||||
void obj_gc_mark(PyVar obj) { if(obj.is_ptr) __obj_gc_mark(obj.get()); }
|
void obj_gc_mark(PyVar obj) { if(obj.is_ptr) __obj_gc_mark(obj.get()); }
|
||||||
void obj_gc_mark(PyObject* p) { if(p) __obj_gc_mark(p); }
|
void obj_gc_mark(PyObject* p) { if(p) __obj_gc_mark(p); }
|
||||||
@ -280,7 +280,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if PK_REGION("Source Execution Methods")
|
#if PK_REGION("Source Execution Methods")
|
||||||
CodeObject_ compile(std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope=false);
|
CodeObject* compile(std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope=false);
|
||||||
Str precompile(std::string_view source, const Str& filename, CompileMode mode);
|
Str precompile(std::string_view source, const Str& filename, CompileMode mode);
|
||||||
PyVar exec(std::string_view source, Str filename, CompileMode mode, PyObject* _module=nullptr);
|
PyVar exec(std::string_view source, Str filename, CompileMode mode, PyObject* _module=nullptr);
|
||||||
PyVar exec(std::string_view source);
|
PyVar exec(std::string_view source);
|
||||||
@ -362,25 +362,25 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if PK_REGION("General Bindings")
|
#if PK_REGION("General Bindings")
|
||||||
PyObject* bind_func(PyObject* obj, StrName name, int argc, NativeFuncC fn, any userdata={}, BindType bt=BindType::DEFAULT);
|
PyObject* bind_func(PyObject* obj, StrName name, int argc, NativeFuncC fn, any userdata={}, BindType bt=BindType_FUNCTION);
|
||||||
PyObject* bind_func(Type type, StrName name, int argc, NativeFuncC fn, any userdata={}, BindType bt=BindType::DEFAULT){
|
PyObject* bind_func(Type type, StrName name, int argc, NativeFuncC fn, any userdata={}, BindType bt=BindType_FUNCTION){
|
||||||
return bind_func(_t(type), name, argc, fn, std::move(userdata), bt);
|
return bind_func(_t(type), name, argc, fn, std::move(userdata), bt);
|
||||||
}
|
}
|
||||||
PyObject* bind_property(PyObject*, const char*, NativeFuncC fget, NativeFuncC fset=nullptr);
|
PyObject* bind_property(PyObject*, const char*, NativeFuncC fget, NativeFuncC fset=nullptr);
|
||||||
template<typename T, typename F, bool ReadOnly=false>
|
template<typename T, typename F, bool ReadOnly=false>
|
||||||
PyObject* bind_field(PyObject*, const char*, F T::*);
|
PyObject* bind_field(PyObject*, const char*, F T::*);
|
||||||
|
|
||||||
PyObject* bind(PyObject*, const char*, NativeFuncC, any userdata={}, BindType bt=BindType::DEFAULT);
|
PyObject* bind(PyObject*, const char*, NativeFuncC, any userdata={}, BindType bt=BindType_FUNCTION);
|
||||||
template<typename Ret, typename... Params>
|
template<typename Ret, typename... Params>
|
||||||
PyObject* bind(PyObject*, const char*, Ret(*)(Params...), BindType bt=BindType::DEFAULT);
|
PyObject* bind(PyObject*, const char*, Ret(*)(Params...), BindType bt=BindType_FUNCTION);
|
||||||
template<typename Ret, typename T, typename... Params>
|
template<typename Ret, typename T, typename... Params>
|
||||||
PyObject* bind(PyObject*, const char*, Ret(T::*)(Params...), BindType bt=BindType::DEFAULT);
|
PyObject* bind(PyObject*, const char*, Ret(T::*)(Params...), BindType bt=BindType_FUNCTION);
|
||||||
|
|
||||||
PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, any userdata={}, BindType bt=BindType::DEFAULT);
|
PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, any userdata={}, BindType bt=BindType_FUNCTION);
|
||||||
template<typename Ret, typename... Params>
|
template<typename Ret, typename... Params>
|
||||||
PyObject* bind(PyObject*, const char*, const char*, Ret(*)(Params...), BindType bt=BindType::DEFAULT);
|
PyObject* bind(PyObject*, const char*, const char*, Ret(*)(Params...), BindType bt=BindType_FUNCTION);
|
||||||
template<typename Ret, typename T, typename... Params>
|
template<typename Ret, typename T, typename... Params>
|
||||||
PyObject* bind(PyObject*, const char*, const char*, Ret(T::*)(Params...), BindType bt=BindType::DEFAULT);
|
PyObject* bind(PyObject*, const char*, const char*, Ret(T::*)(Params...), BindType bt=BindType_FUNCTION);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if PK_REGION("Error Reporting Methods")
|
#if PK_REGION("Error Reporting Methods")
|
||||||
@ -494,7 +494,7 @@ public:
|
|||||||
#if PK_DEBUG_CEVAL_STEP
|
#if PK_DEBUG_CEVAL_STEP
|
||||||
void __log_s_data(const char* title = nullptr);
|
void __log_s_data(const char* title = nullptr);
|
||||||
#endif
|
#endif
|
||||||
PyVar __py_exec_internal(const CodeObject_& code, PyVar globals, PyVar locals);
|
PyVar __py_exec_internal(const CodeObject* code, PyVar globals, PyVar locals);
|
||||||
void __breakpoint();
|
void __breakpoint();
|
||||||
PyVar __format_object(PyVar, Str);
|
PyVar __format_object(PyVar, Str);
|
||||||
PyVar __run_top_frame();
|
PyVar __run_top_frame();
|
||||||
|
|||||||
66
include/pocketpy/objects/codeobject.h
Normal file
66
include/pocketpy/objects/codeobject.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BC_NOARG 0
|
||||||
|
#define BC_KEEPLINE -1
|
||||||
|
|
||||||
|
typedef enum BindType {
|
||||||
|
BindType_FUNCTION,
|
||||||
|
BindType_STATICMETHOD,
|
||||||
|
BindType_CLASSMETHOD,
|
||||||
|
} BindType;
|
||||||
|
|
||||||
|
typedef enum FuncType {
|
||||||
|
FuncType_UNSET,
|
||||||
|
FuncType_NORMAL,
|
||||||
|
FuncType_SIMPLE,
|
||||||
|
FuncType_EMPTY,
|
||||||
|
FuncType_GENERATOR,
|
||||||
|
} FuncType;
|
||||||
|
|
||||||
|
typedef enum NameScope {
|
||||||
|
NAME_LOCAL,
|
||||||
|
NAME_GLOBAL,
|
||||||
|
NAME_GLOBAL_UNKNOWN
|
||||||
|
} NameScope;
|
||||||
|
|
||||||
|
typedef enum CodeBlockType {
|
||||||
|
CodeBlockType_NO_BLOCK,
|
||||||
|
CodeBlockType_FOR_LOOP,
|
||||||
|
CodeBlockType_WHILE_LOOP,
|
||||||
|
CodeBlockType_CONTEXT_MANAGER,
|
||||||
|
CodeBlockType_TRY_EXCEPT,
|
||||||
|
} CodeBlockType;
|
||||||
|
|
||||||
|
typedef enum Opcode {
|
||||||
|
#define OPCODE(name) OP_##name,
|
||||||
|
#include "pocketpy/xmacros/opcodes.h"
|
||||||
|
#undef OPCODE
|
||||||
|
} Opcode;
|
||||||
|
|
||||||
|
typedef struct Bytecode {
|
||||||
|
uint8_t op;
|
||||||
|
uint16_t arg;
|
||||||
|
} Bytecode;
|
||||||
|
|
||||||
|
void Bytecode__set_signed_arg(Bytecode* self, int arg);
|
||||||
|
bool Bytecode__is_forward_jump(const Bytecode* self);
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct CodeBlock {
|
||||||
|
CodeBlockType type;
|
||||||
|
int parent; // parent index in blocks
|
||||||
|
int start; // start index of this block in codes, inclusive
|
||||||
|
int end; // end index of this block in codes, exclusive
|
||||||
|
int end2; // ...
|
||||||
|
} CodeBlock;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@ -6,68 +6,14 @@
|
|||||||
#include "pocketpy/objects/namedict.hpp"
|
#include "pocketpy/objects/namedict.hpp"
|
||||||
#include "pocketpy/objects/sourcedata.h"
|
#include "pocketpy/objects/sourcedata.h"
|
||||||
#include "pocketpy/common/smallmap.h"
|
#include "pocketpy/common/smallmap.h"
|
||||||
|
#include "pocketpy/objects/codeobject.h"
|
||||||
|
|
||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
|
|
||||||
typedef PyVar (*NativeFuncC)(VM*, ArgsView);
|
typedef PyVar (*NativeFuncC)(VM*, ArgsView);
|
||||||
|
|
||||||
enum class BindType {
|
|
||||||
DEFAULT,
|
|
||||||
STATICMETHOD,
|
|
||||||
CLASSMETHOD,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum NameScope { NAME_LOCAL, NAME_GLOBAL, NAME_GLOBAL_UNKNOWN };
|
|
||||||
|
|
||||||
enum Opcode : uint8_t {
|
|
||||||
|
|
||||||
#define OPCODE(name) OP_##name,
|
|
||||||
#include "pocketpy/xmacros/opcodes.h"
|
|
||||||
#undef OPCODE
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Bytecode {
|
|
||||||
uint8_t op;
|
|
||||||
uint16_t arg;
|
|
||||||
|
|
||||||
void set_signed_arg(int arg) {
|
|
||||||
assert(arg >= INT16_MIN && arg <= INT16_MAX);
|
|
||||||
this->arg = (int16_t)arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_forward_jump() const { return op >= OP_JUMP_FORWARD && op <= OP_LOOP_BREAK; }
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class CodeBlockType {
|
|
||||||
NO_BLOCK,
|
|
||||||
FOR_LOOP,
|
|
||||||
WHILE_LOOP,
|
|
||||||
CONTEXT_MANAGER,
|
|
||||||
TRY_EXCEPT,
|
|
||||||
};
|
|
||||||
|
|
||||||
const inline uint8_t BC_NOARG = 0;
|
|
||||||
const inline int BC_KEEPLINE = -1;
|
|
||||||
|
|
||||||
struct CodeBlock {
|
|
||||||
CodeBlockType type;
|
|
||||||
int parent; // parent index in blocks
|
|
||||||
int start; // start index of this block in codes, inclusive
|
|
||||||
int end; // end index of this block in codes, exclusive
|
|
||||||
int end2; // ...
|
|
||||||
|
|
||||||
CodeBlock(CodeBlockType type, int parent, int start) :
|
|
||||||
type(type), parent(parent), start(start), end(-1), end2(-1) {}
|
|
||||||
|
|
||||||
int get_break_end() const {
|
|
||||||
if(end2 != -1) return end2;
|
|
||||||
return end;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CodeObject;
|
struct CodeObject;
|
||||||
struct FuncDecl;
|
struct FuncDecl;
|
||||||
using CodeObject_ = std::shared_ptr<CodeObject>;
|
|
||||||
using FuncDecl_ = std::shared_ptr<FuncDecl>;
|
using FuncDecl_ = std::shared_ptr<FuncDecl>;
|
||||||
|
|
||||||
struct CodeObject {
|
struct CodeObject {
|
||||||
@ -97,13 +43,11 @@ struct CodeObject {
|
|||||||
int start_line;
|
int start_line;
|
||||||
int end_line;
|
int end_line;
|
||||||
|
|
||||||
const CodeBlock& _get_block_codei(int codei) const { return blocks[lines[codei].iblock]; }
|
|
||||||
|
|
||||||
void _gc_mark(VM*) const;
|
void _gc_mark(VM*) const;
|
||||||
|
|
||||||
CodeObject(pkpy_SourceData_ src, const Str& name) :
|
CodeObject(pkpy_SourceData_ src, const Str& name) :
|
||||||
src(src), name(name), nlocals(0), start_line(-1), end_line(-1) {
|
src(src), name(name), nlocals(0), start_line(-1), end_line(-1) {
|
||||||
blocks.push_back(CodeBlock(CodeBlockType::NO_BLOCK, -1, 0));
|
blocks.push_back(CodeBlock{CodeBlockType_NO_BLOCK, -1, 0, -1, -1});
|
||||||
c11_smallmap_n2i__ctor(&varnames_inv);
|
c11_smallmap_n2i__ctor(&varnames_inv);
|
||||||
c11_smallmap_n2i__ctor(&labels);
|
c11_smallmap_n2i__ctor(&labels);
|
||||||
PK_INCREF(src);
|
PK_INCREF(src);
|
||||||
@ -116,25 +60,18 @@ struct CodeObject {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class FuncType {
|
|
||||||
UNSET,
|
|
||||||
NORMAL,
|
|
||||||
SIMPLE,
|
|
||||||
EMPTY,
|
|
||||||
GENERATOR,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FuncDecl {
|
struct FuncDecl {
|
||||||
|
PK_ALWAYS_PASS_BY_POINTER(FuncDecl)
|
||||||
struct KwArg {
|
struct KwArg {
|
||||||
int index; // index in co->varnames
|
int index; // index in co->varnames
|
||||||
StrName key; // name of this argument
|
StrName key; // name of this argument
|
||||||
PyVar value; // default value
|
PyVar value; // default value
|
||||||
};
|
};
|
||||||
|
|
||||||
CodeObject_ code; // code object of this function
|
CodeObject* code; // strong ref
|
||||||
|
|
||||||
small_vector_2<int, 8> args; // indices in co->varnames
|
small_vector_2<int, 8> args; // indices in co->varnames
|
||||||
small_vector_2<KwArg, 6> kwargs; // indices in co->varnames
|
c11_vector/*T=KwArg*/ kwargs; // indices in co->varnames
|
||||||
|
|
||||||
int starred_arg = -1; // index in co->varnames, -1 if no *arg
|
int starred_arg = -1; // index in co->varnames, -1 if no *arg
|
||||||
int starred_kwarg = -1; // index in co->varnames, -1 if no **kwarg
|
int starred_kwarg = -1; // index in co->varnames, -1 if no **kwarg
|
||||||
@ -142,21 +79,25 @@ struct FuncDecl {
|
|||||||
|
|
||||||
const char* docstring; // docstring of this function (weak ref)
|
const char* docstring; // docstring of this function (weak ref)
|
||||||
|
|
||||||
FuncType type = FuncType::UNSET;
|
FuncType type = FuncType_UNSET;
|
||||||
c11_smallmap_n2i kw_to_index;
|
c11_smallmap_n2i kw_to_index;
|
||||||
|
|
||||||
void add_kwarg(int index, StrName key, PyVar value) {
|
void add_kwarg(int index, StrName key, PyVar value) {
|
||||||
c11_smallmap_n2i__set(&kw_to_index, key.index, index);
|
c11_smallmap_n2i__set(&kw_to_index, key.index, index);
|
||||||
kwargs.push_back(KwArg{index, key, value});
|
c11_vector__push(KwArg, &kwargs, (KwArg{index, key.index, value}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _gc_mark(VM*) const;
|
void _gc_mark(VM*) const;
|
||||||
|
|
||||||
FuncDecl(){
|
FuncDecl(CodeObject* code){
|
||||||
|
this->code = code;
|
||||||
|
c11_vector__ctor(&kwargs, sizeof(KwArg));
|
||||||
c11_smallmap_n2i__ctor(&kw_to_index);
|
c11_smallmap_n2i__ctor(&kw_to_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
~FuncDecl(){
|
~FuncDecl(){
|
||||||
|
delete code;
|
||||||
|
c11_vector__dtor(&kwargs);
|
||||||
c11_smallmap_n2i__dtor(&kw_to_index);
|
c11_smallmap_n2i__dtor(&kw_to_index);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
#include "pocketpy/compiler/compiler.hpp"
|
#include "pocketpy/compiler/compiler.hpp"
|
||||||
#include "pocketpy/common/config.h"
|
#include "pocketpy/common/config.h"
|
||||||
#include "pocketpy/interpreter/vm.hpp"
|
#include "pocketpy/interpreter/vm.hpp"
|
||||||
|
#include "pocketpy/objects/codeobject.hpp"
|
||||||
|
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
|
|
||||||
@ -19,16 +20,16 @@ NameScope Compiler::name_scope() const noexcept{
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
CodeObject_ Compiler::push_global_context() noexcept{
|
CodeObject* Compiler::push_global_context() noexcept{
|
||||||
CodeObject_ co = std::make_shared<CodeObject>(lexer.src, static_cast<const Str&>(lexer.src->filename));
|
CodeObject* co = new CodeObject(lexer.src, static_cast<const Str&>(lexer.src->filename));
|
||||||
co->start_line = __i == 0 ? 1 : prev().line;
|
co->start_line = __i == 0 ? 1 : prev().line;
|
||||||
contexts.push_back(CodeEmitContext(vm, co, contexts.size()));
|
contexts.push_back(CodeEmitContext(vm, co, contexts.size()));
|
||||||
return co;
|
return co;
|
||||||
}
|
}
|
||||||
|
|
||||||
FuncDecl_ Compiler::push_f_context(Str name) noexcept{
|
FuncDecl_ Compiler::push_f_context(Str name) noexcept{
|
||||||
FuncDecl_ decl = std::make_shared<FuncDecl>();
|
CodeObject* co = new CodeObject(lexer.src, name);
|
||||||
decl->code = std::make_shared<CodeObject>(lexer.src, name);
|
FuncDecl_ decl = std::make_shared<FuncDecl>(co);
|
||||||
decl->code->start_line = __i == 0 ? 1 : prev().line;
|
decl->code->start_line = __i == 0 ? 1 : prev().line;
|
||||||
decl->nested = name_scope() == NAME_LOCAL;
|
decl->nested = name_scope() == NAME_LOCAL;
|
||||||
contexts.push_back(CodeEmitContext(vm, decl->code, contexts.size()));
|
contexts.push_back(CodeEmitContext(vm, decl->code, contexts.size()));
|
||||||
@ -60,9 +61,11 @@ Error* Compiler::pop_context() noexcept{
|
|||||||
for(int i = 0; i < codes.size(); i++) {
|
for(int i = 0; i < codes.size(); i++) {
|
||||||
Bytecode& bc = codes[i];
|
Bytecode& bc = codes[i];
|
||||||
if(bc.op == OP_LOOP_CONTINUE) {
|
if(bc.op == OP_LOOP_CONTINUE) {
|
||||||
bc.set_signed_arg(ctx()->co->blocks[bc.arg].start - i);
|
CodeBlock* block = &ctx()->co->blocks[bc.arg];
|
||||||
|
Bytecode__set_signed_arg(&bc, block->start - i);
|
||||||
} else if(bc.op == OP_LOOP_BREAK) {
|
} else if(bc.op == OP_LOOP_BREAK) {
|
||||||
bc.set_signed_arg(ctx()->co->blocks[bc.arg].get_break_end() - i);
|
CodeBlock* block = &ctx()->co->blocks[bc.arg];
|
||||||
|
Bytecode__set_signed_arg(&bc, (block->end2 != -1 ? block->end2 : block->end) - i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// pre-compute func->is_simple
|
// pre-compute func->is_simple
|
||||||
@ -71,7 +74,7 @@ Error* Compiler::pop_context() noexcept{
|
|||||||
// check generator
|
// check generator
|
||||||
for(Bytecode bc: func->code->codes) {
|
for(Bytecode bc: func->code->codes) {
|
||||||
if(bc.op == OP_YIELD_VALUE || bc.op == OP_FOR_ITER_YIELD_VALUE) {
|
if(bc.op == OP_YIELD_VALUE || bc.op == OP_FOR_ITER_YIELD_VALUE) {
|
||||||
func->type = FuncType::GENERATOR;
|
func->type = FuncType_GENERATOR;
|
||||||
for(Bytecode bc: func->code->codes) {
|
for(Bytecode bc: func->code->codes) {
|
||||||
if(bc.op == OP_RETURN_VALUE && bc.arg == BC_NOARG) {
|
if(bc.op == OP_RETURN_VALUE && bc.arg == BC_NOARG) {
|
||||||
return SyntaxError("'return' with argument inside generator function");
|
return SyntaxError("'return' with argument inside generator function");
|
||||||
@ -80,26 +83,26 @@ Error* Compiler::pop_context() noexcept{
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(func->type == FuncType::UNSET) {
|
if(func->type == FuncType_UNSET) {
|
||||||
bool is_simple = true;
|
bool is_simple = true;
|
||||||
if(func->kwargs.size() > 0) is_simple = false;
|
if(func->kwargs.count > 0) is_simple = false;
|
||||||
if(func->starred_arg >= 0) is_simple = false;
|
if(func->starred_arg >= 0) is_simple = false;
|
||||||
if(func->starred_kwarg >= 0) is_simple = false;
|
if(func->starred_kwarg >= 0) is_simple = false;
|
||||||
|
|
||||||
if(is_simple) {
|
if(is_simple) {
|
||||||
func->type = FuncType::SIMPLE;
|
func->type = FuncType_SIMPLE;
|
||||||
|
|
||||||
bool is_empty = false;
|
bool is_empty = false;
|
||||||
if(func->code->codes.size() == 1) {
|
if(func->code->codes.size() == 1) {
|
||||||
Bytecode bc = func->code->codes[0];
|
Bytecode bc = func->code->codes[0];
|
||||||
if(bc.op == OP_RETURN_VALUE && bc.arg == 1) { is_empty = true; }
|
if(bc.op == OP_RETURN_VALUE && bc.arg == 1) { is_empty = true; }
|
||||||
}
|
}
|
||||||
if(is_empty) func->type = FuncType::EMPTY;
|
if(is_empty) func->type = FuncType_EMPTY;
|
||||||
} else
|
} else
|
||||||
func->type = FuncType::NORMAL;
|
func->type = FuncType_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(func->type != FuncType::UNSET);
|
assert(func->type != FuncType_UNSET);
|
||||||
}
|
}
|
||||||
contexts.back().s_clean();
|
contexts.back().s_clean();
|
||||||
contexts.pop_back();
|
contexts.pop_back();
|
||||||
@ -730,7 +733,7 @@ Error* Compiler::compile_if_stmt() noexcept{
|
|||||||
|
|
||||||
Error* Compiler::compile_while_loop() noexcept{
|
Error* Compiler::compile_while_loop() noexcept{
|
||||||
Error* err;
|
Error* err;
|
||||||
CodeBlock* block = ctx()->enter_block(CodeBlockType::WHILE_LOOP);
|
CodeBlock* block = ctx()->enter_block(CodeBlockType_WHILE_LOOP);
|
||||||
check(EXPR()); // condition
|
check(EXPR()); // condition
|
||||||
ctx()->s_emit_top();
|
ctx()->s_emit_top();
|
||||||
int patch = ctx()->emit_(OP_POP_JUMP_IF_FALSE, BC_NOARG, prev().line);
|
int patch = ctx()->emit_(OP_POP_JUMP_IF_FALSE, BC_NOARG, prev().line);
|
||||||
@ -753,7 +756,7 @@ Error* Compiler::compile_for_loop() noexcept{
|
|||||||
check(EXPR_TUPLE()); // [vars, iter]
|
check(EXPR_TUPLE()); // [vars, iter]
|
||||||
ctx()->s_emit_top(); // [vars]
|
ctx()->s_emit_top(); // [vars]
|
||||||
ctx()->emit_(OP_GET_ITER_NEW, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit_(OP_GET_ITER_NEW, BC_NOARG, BC_KEEPLINE);
|
||||||
CodeBlock* block = ctx()->enter_block(CodeBlockType::FOR_LOOP);
|
CodeBlock* block = ctx()->enter_block(CodeBlockType_FOR_LOOP);
|
||||||
int for_codei = ctx()->emit_(OP_FOR_ITER, ctx()->curr_iblock, BC_KEEPLINE);
|
int for_codei = ctx()->emit_(OP_FOR_ITER, ctx()->curr_iblock, BC_KEEPLINE);
|
||||||
Expr* vars = ctx()->s_popx();
|
Expr* vars = ctx()->s_popx();
|
||||||
bool ok = vars->emit_store(ctx());
|
bool ok = vars->emit_store(ctx());
|
||||||
@ -773,7 +776,7 @@ Error* Compiler::compile_for_loop() noexcept{
|
|||||||
|
|
||||||
Error* Compiler::compile_try_except() noexcept{
|
Error* Compiler::compile_try_except() noexcept{
|
||||||
Error* err;
|
Error* err;
|
||||||
ctx()->enter_block(CodeBlockType::TRY_EXCEPT);
|
ctx()->enter_block(CodeBlockType_TRY_EXCEPT);
|
||||||
ctx()->emit_(OP_TRY_ENTER, BC_NOARG, prev().line);
|
ctx()->emit_(OP_TRY_ENTER, BC_NOARG, prev().line);
|
||||||
check(compile_block_body());
|
check(compile_block_body());
|
||||||
small_vector_2<int, 8> patches;
|
small_vector_2<int, 8> patches;
|
||||||
@ -822,7 +825,7 @@ Error* Compiler::compile_try_except() noexcept{
|
|||||||
i64 target = ctx()->co->codes.size() + 2;
|
i64 target = ctx()->co->codes.size() + 2;
|
||||||
ctx()->emit_(OP_LOAD_CONST, ctx()->add_const(VAR(target)), BC_KEEPLINE);
|
ctx()->emit_(OP_LOAD_CONST, ctx()->add_const(VAR(target)), BC_KEEPLINE);
|
||||||
int i = ctx()->emit_(OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE);
|
int i = ctx()->emit_(OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE);
|
||||||
ctx()->co->codes[i].set_signed_arg(finally_entry - i);
|
Bytecode__set_signed_arg(&ctx()->co->codes[i], finally_entry - i);
|
||||||
}
|
}
|
||||||
ctx()->emit_(OP_RE_RAISE, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit_(OP_RE_RAISE, BC_NOARG, BC_KEEPLINE);
|
||||||
|
|
||||||
@ -833,7 +836,7 @@ Error* Compiler::compile_try_except() noexcept{
|
|||||||
i64 target = ctx()->co->codes.size() + 2;
|
i64 target = ctx()->co->codes.size() + 2;
|
||||||
ctx()->emit_(OP_LOAD_CONST, ctx()->add_const(VAR(target)), BC_KEEPLINE);
|
ctx()->emit_(OP_LOAD_CONST, ctx()->add_const(VAR(target)), BC_KEEPLINE);
|
||||||
int i = ctx()->emit_(OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE);
|
int i = ctx()->emit_(OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE);
|
||||||
ctx()->co->codes[i].set_signed_arg(finally_entry - i);
|
Bytecode__set_signed_arg(&ctx()->co->codes[i], finally_entry - i);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -954,7 +957,7 @@ Error* Compiler::compile_stmt() noexcept{
|
|||||||
ctx()->s_emit_top();
|
ctx()->s_emit_top();
|
||||||
|
|
||||||
ctx()->emit_(OP_GET_ITER_NEW, BC_NOARG, kw_line);
|
ctx()->emit_(OP_GET_ITER_NEW, BC_NOARG, kw_line);
|
||||||
ctx()->enter_block(CodeBlockType::FOR_LOOP);
|
ctx()->enter_block(CodeBlockType_FOR_LOOP);
|
||||||
ctx()->emit_(OP_FOR_ITER_YIELD_VALUE, BC_NOARG, kw_line);
|
ctx()->emit_(OP_FOR_ITER_YIELD_VALUE, BC_NOARG, kw_line);
|
||||||
ctx()->emit_(OP_LOOP_CONTINUE, ctx()->get_loop(), kw_line);
|
ctx()->emit_(OP_LOOP_CONTINUE, ctx()->get_loop(), kw_line);
|
||||||
ctx()->exit_block();
|
ctx()->exit_block();
|
||||||
@ -1019,7 +1022,7 @@ Error* Compiler::compile_stmt() noexcept{
|
|||||||
case TK_WITH: {
|
case TK_WITH: {
|
||||||
check(EXPR()); // [ <expr> ]
|
check(EXPR()); // [ <expr> ]
|
||||||
ctx()->s_emit_top();
|
ctx()->s_emit_top();
|
||||||
ctx()->enter_block(CodeBlockType::CONTEXT_MANAGER);
|
ctx()->enter_block(CodeBlockType_CONTEXT_MANAGER);
|
||||||
Expr* as_name = nullptr;
|
Expr* as_name = nullptr;
|
||||||
if(match(TK_AS)) {
|
if(match(TK_AS)) {
|
||||||
consume(TK_ID);
|
consume(TK_ID);
|
||||||
@ -1163,8 +1166,8 @@ Error* Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints) noexcep
|
|||||||
for(int j: decl->args) {
|
for(int j: decl->args) {
|
||||||
if(decl->code->varnames[j] == name) return SyntaxError("duplicate argument name");
|
if(decl->code->varnames[j] == name) return SyntaxError("duplicate argument name");
|
||||||
}
|
}
|
||||||
for(auto& kv: decl->kwargs) {
|
c11_vector__foreach(FuncDecl::KwArg, &decl->kwargs, kv) {
|
||||||
if(decl->code->varnames[kv.index] == name) return SyntaxError("duplicate argument name");
|
if(decl->code->varnames[kv->index] == name) return SyntaxError("duplicate argument name");
|
||||||
}
|
}
|
||||||
if(decl->starred_arg != -1 && decl->code->varnames[decl->starred_arg] == name) {
|
if(decl->starred_arg != -1 && decl->code->varnames[decl->starred_arg] == name) {
|
||||||
return SyntaxError("duplicate argument name");
|
return SyntaxError("duplicate argument name");
|
||||||
@ -1288,7 +1291,7 @@ Compiler::Compiler(VM* vm, std::string_view source, const Str& filename, Compile
|
|||||||
init_pratt_rules();
|
init_pratt_rules();
|
||||||
}
|
}
|
||||||
|
|
||||||
Error* Compiler::compile(CodeObject_* out) noexcept{
|
Error* Compiler::compile(CodeObject** out) noexcept{
|
||||||
assert(__i == 0); // make sure it is the first time to compile
|
assert(__i == 0); // make sure it is the first time to compile
|
||||||
|
|
||||||
Error* err;
|
Error* err;
|
||||||
@ -1301,7 +1304,7 @@ Error* Compiler::compile(CodeObject_* out) noexcept{
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
CodeObject_ code = push_global_context();
|
CodeObject* code = push_global_context();
|
||||||
|
|
||||||
assert(curr().type == TK_SOF);
|
assert(curr().type == TK_SOF);
|
||||||
advance(); // skip @sof, so prev() is always valid
|
advance(); // skip @sof, so prev() is always valid
|
||||||
|
|||||||
59
src/compiler/expr.c
Normal file
59
src/compiler/expr.c
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// #include "pocketpy/compiler/expr.h"
|
||||||
|
// #include "pocketpy/common/memorypool.h"
|
||||||
|
|
||||||
|
// static bool default_false(const pk_Expr*) { return false; }
|
||||||
|
// static int default_zero(const pk_Expr*) { return 0; }
|
||||||
|
// static void default_dtor(pk_Expr*) {}
|
||||||
|
|
||||||
|
// void pk_ExprVt__ctor(pk_ExprVt* vt){
|
||||||
|
// vt->dtor = default_dtor;
|
||||||
|
// vt->is_literal = default_false;
|
||||||
|
// vt->is_json_object = default_false;
|
||||||
|
// vt->is_attrib = default_false;
|
||||||
|
// vt->is_subscr = default_false;
|
||||||
|
// vt->is_compare = default_false;
|
||||||
|
// vt->star_level = default_zero;
|
||||||
|
// vt->is_tuple = default_false;
|
||||||
|
// vt->is_name = default_false;
|
||||||
|
// vt->emit_ = NULL; // must be set
|
||||||
|
// vt->emit_del = NULL;
|
||||||
|
// vt->emit_store = NULL;
|
||||||
|
// vt->emit_inplace = NULL;
|
||||||
|
// vt->emit_store_inplace = NULL;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void pk_Expr__emit_(pk_Expr* self, pk_CodeEmitContext* ctx){
|
||||||
|
// assert(self->vt->emit_);
|
||||||
|
// self->vt->emit_(self, ctx);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// bool pk_Expr__emit_del(pk_Expr* self, pk_CodeEmitContext* ctx){
|
||||||
|
// if(!self->vt->emit_del) return false;
|
||||||
|
// return self->vt->emit_del(self, ctx);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// bool pk_Expr__emit_store(pk_Expr* self, pk_CodeEmitContext* ctx){
|
||||||
|
// if(!self->vt->emit_store) return false;
|
||||||
|
// return self->vt->emit_store(self, ctx);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void pk_Expr__emit_inplace(pk_Expr* self, pk_CodeEmitContext* ctx){
|
||||||
|
// if(!self->vt->emit_inplace){
|
||||||
|
// pk_Expr__emit_(self, ctx);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// self->vt->emit_inplace(self, ctx);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// bool pk_Expr__emit_store_inplace(pk_Expr* self, pk_CodeEmitContext* ctx){
|
||||||
|
// if(!self->vt->emit_store_inplace){
|
||||||
|
// return pk_Expr__emit_store(self, ctx);
|
||||||
|
// }
|
||||||
|
// return self->vt->emit_store_inplace(self, ctx);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void pk_Expr__delete(pk_Expr* self){
|
||||||
|
// if(!self) return;
|
||||||
|
// self->vt->dtor(self);
|
||||||
|
// PoolExpr_dealloc(self);
|
||||||
|
// }
|
||||||
@ -16,15 +16,15 @@ inline bool is_small_int(i64 value) { return value >= INT16_MIN && value <= INT1
|
|||||||
int CodeEmitContext::get_loop() const noexcept{
|
int CodeEmitContext::get_loop() const noexcept{
|
||||||
int index = curr_iblock;
|
int index = curr_iblock;
|
||||||
while(index >= 0) {
|
while(index >= 0) {
|
||||||
if(co->blocks[index].type == CodeBlockType::FOR_LOOP) break;
|
if(co->blocks[index].type == CodeBlockType_FOR_LOOP) break;
|
||||||
if(co->blocks[index].type == CodeBlockType::WHILE_LOOP) break;
|
if(co->blocks[index].type == CodeBlockType_WHILE_LOOP) break;
|
||||||
index = co->blocks[index].parent;
|
index = co->blocks[index].parent;
|
||||||
}
|
}
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
CodeBlock* CodeEmitContext::enter_block(CodeBlockType type) noexcept{
|
CodeBlock* CodeEmitContext::enter_block(CodeBlockType type) noexcept{
|
||||||
co->blocks.push_back(CodeBlock(type, curr_iblock, (int)co->codes.size()));
|
co->blocks.push_back(CodeBlock{type, curr_iblock, (int)co->codes.size(), -1, -1});
|
||||||
curr_iblock = co->blocks.size() - 1;
|
curr_iblock = co->blocks.size() - 1;
|
||||||
return &co->blocks[curr_iblock];
|
return &co->blocks[curr_iblock];
|
||||||
}
|
}
|
||||||
@ -34,7 +34,7 @@ void CodeEmitContext::exit_block() noexcept{
|
|||||||
co->blocks[curr_iblock].end = co->codes.size();
|
co->blocks[curr_iblock].end = co->codes.size();
|
||||||
curr_iblock = co->blocks[curr_iblock].parent;
|
curr_iblock = co->blocks[curr_iblock].parent;
|
||||||
assert(curr_iblock >= 0);
|
assert(curr_iblock >= 0);
|
||||||
if(curr_type == CodeBlockType::FOR_LOOP) {
|
if(curr_type == CodeBlockType_FOR_LOOP) {
|
||||||
// add a no op here to make block check work
|
// add a no op here to make block check work
|
||||||
emit_(OP_NO_OP, BC_NOARG, BC_KEEPLINE, true);
|
emit_(OP_NO_OP, BC_NOARG, BC_KEEPLINE, true);
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ int CodeEmitContext::emit_int(i64 value, int line) noexcept{
|
|||||||
|
|
||||||
void CodeEmitContext::patch_jump(int index) noexcept{
|
void CodeEmitContext::patch_jump(int index) noexcept{
|
||||||
int target = co->codes.size();
|
int target = co->codes.size();
|
||||||
co->codes[index].set_signed_arg(target - index);
|
Bytecode__set_signed_arg(&co->codes[index], target - index);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CodeEmitContext::add_label(StrName name) noexcept{
|
bool CodeEmitContext::add_label(StrName name) noexcept{
|
||||||
@ -381,7 +381,7 @@ void CompExpr::emit_(CodeEmitContext* ctx) {
|
|||||||
ctx->emit_(op0, 0, line);
|
ctx->emit_(op0, 0, line);
|
||||||
iter->emit_(ctx);
|
iter->emit_(ctx);
|
||||||
ctx->emit_(OP_GET_ITER, BC_NOARG, BC_KEEPLINE);
|
ctx->emit_(OP_GET_ITER, BC_NOARG, BC_KEEPLINE);
|
||||||
ctx->enter_block(CodeBlockType::FOR_LOOP);
|
ctx->enter_block(CodeBlockType_FOR_LOOP);
|
||||||
int curr_iblock = ctx->curr_iblock;
|
int curr_iblock = ctx->curr_iblock;
|
||||||
int for_codei = ctx->emit_(OP_FOR_ITER, curr_iblock, BC_KEEPLINE);
|
int for_codei = ctx->emit_(OP_FOR_ITER, curr_iblock, BC_KEEPLINE);
|
||||||
bool ok = vars->emit_store(ctx);
|
bool ok = vars->emit_store(ctx);
|
||||||
|
|||||||
@ -795,8 +795,9 @@ PyVar VM::__run_top_frame() {
|
|||||||
PyVar _0 = frame->co->consts[byte.arg];
|
PyVar _0 = frame->co->consts[byte.arg];
|
||||||
std::string_view string = CAST(Str&, _0).sv();
|
std::string_view string = CAST(Str&, _0).sv();
|
||||||
// TODO: optimize this
|
// TODO: optimize this
|
||||||
CodeObject_ code = vm->compile(string, "<eval>", EVAL_MODE, true);
|
CodeObject* code = vm->compile(string, "<eval>", EVAL_MODE, true);
|
||||||
_0 = vm->_exec(code.get(), frame->_module, frame->_callable, frame->_locals);
|
_0 = vm->_exec(code, frame->_module, frame->_callable, frame->_locals);
|
||||||
|
delete code; // leak on error
|
||||||
PUSH(_0);
|
PUSH(_0);
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
|
|||||||
@ -84,7 +84,7 @@ void Struct::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
return vm->new_user_object<Struct>(std::move(buffer));
|
return vm->new_user_object<Struct>(std::move(buffer));
|
||||||
},
|
},
|
||||||
{},
|
{},
|
||||||
BindType::STATICMETHOD);
|
BindType_STATICMETHOD);
|
||||||
|
|
||||||
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) {
|
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) {
|
||||||
Struct& self = _CAST(Struct&, obj);
|
Struct& self = _CAST(Struct&, obj);
|
||||||
|
|||||||
@ -29,7 +29,7 @@ int Frame::prepare_jump_exception_handler(ValueStack* _s) {
|
|||||||
// try to find a parent try block
|
// try to find a parent try block
|
||||||
int i = co->lines[ip()].iblock;
|
int i = co->lines[ip()].iblock;
|
||||||
while(i >= 0) {
|
while(i >= 0) {
|
||||||
if(co->blocks[i].type == CodeBlockType::TRY_EXCEPT) break;
|
if(co->blocks[i].type == CodeBlockType_TRY_EXCEPT) break;
|
||||||
i = co->blocks[i].parent;
|
i = co->blocks[i].parent;
|
||||||
}
|
}
|
||||||
if(i < 0) return -1;
|
if(i < 0) return -1;
|
||||||
@ -42,9 +42,9 @@ int Frame::prepare_jump_exception_handler(ValueStack* _s) {
|
|||||||
|
|
||||||
int Frame::_exit_block(ValueStack* _s, int i) {
|
int Frame::_exit_block(ValueStack* _s, int i) {
|
||||||
auto type = co->blocks[i].type;
|
auto type = co->blocks[i].type;
|
||||||
if(type == CodeBlockType::FOR_LOOP) {
|
if(type == CodeBlockType_FOR_LOOP) {
|
||||||
_s->pop(); // pop the iterator
|
_s->pop(); // pop the iterator
|
||||||
} else if(type == CodeBlockType::CONTEXT_MANAGER) {
|
} else if(type == CodeBlockType_CONTEXT_MANAGER) {
|
||||||
_s->pop();
|
_s->pop();
|
||||||
}
|
}
|
||||||
return co->blocks[i].parent;
|
return co->blocks[i].parent;
|
||||||
|
|||||||
@ -201,13 +201,16 @@ bool VM::issubclass(Type cls, Type base) {
|
|||||||
|
|
||||||
PyVar VM::exec(std::string_view source, Str filename, CompileMode mode, PyObject* _module) {
|
PyVar VM::exec(std::string_view source, Str filename, CompileMode mode, PyObject* _module) {
|
||||||
if(_module == nullptr) _module = _main;
|
if(_module == nullptr) _module = _main;
|
||||||
|
CodeObject* code = NULL;
|
||||||
try {
|
try {
|
||||||
#if PK_DEBUG_PRECOMPILED_EXEC == 1
|
#if PK_DEBUG_PRECOMPILED_EXEC == 1
|
||||||
Str precompiled = vm->precompile(source, filename, mode);
|
Str precompiled = vm->precompile(source, filename, mode);
|
||||||
source = precompiled.sv();
|
source = precompiled.sv();
|
||||||
#endif
|
#endif
|
||||||
CodeObject_ code = compile(source, filename, mode);
|
code = compile(source, filename, mode);
|
||||||
return _exec(code, _module);
|
PyVar retval = _exec(code, _module);
|
||||||
|
delete code; // leak if exception occurs
|
||||||
|
return retval;
|
||||||
} catch(TopLevelException e) {
|
} catch(TopLevelException e) {
|
||||||
stderr_write(e.summary() + "\n");
|
stderr_write(e.summary() + "\n");
|
||||||
} catch(const std::exception& e) {
|
} catch(const std::exception& e) {
|
||||||
@ -218,6 +221,7 @@ PyVar VM::exec(std::string_view source, Str filename, CompileMode mode, PyObject
|
|||||||
Str msg = "An unknown exception occurred! It could be a bug. Please report it to @blueloveTH on GitHub.\n";
|
Str msg = "An unknown exception occurred! It could be a bug. Please report it to @blueloveTH on GitHub.\n";
|
||||||
stderr_write(msg);
|
stderr_write(msg);
|
||||||
}
|
}
|
||||||
|
delete code;
|
||||||
callstack.clear();
|
callstack.clear();
|
||||||
s_data.clear();
|
s_data.clear();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -410,12 +414,12 @@ PyObject* VM::py_import(Str path, bool throw_err) {
|
|||||||
// _lazy_modules.erase(it); // no need to erase
|
// _lazy_modules.erase(it); // no need to erase
|
||||||
}
|
}
|
||||||
auto _ = __import_context.scope(path, is_init);
|
auto _ = __import_context.scope(path, is_init);
|
||||||
CodeObject_ code = compile(source, filename, EXEC_MODE);
|
|
||||||
|
|
||||||
Str name_cpnt = path_cpnts.back();
|
Str name_cpnt = path_cpnts.back();
|
||||||
path_cpnts.pop_back();
|
path_cpnts.pop_back();
|
||||||
PyObject* new_mod = new_module(name_cpnt, f_join(path_cpnts));
|
PyObject* new_mod = new_module(name_cpnt, f_join(path_cpnts));
|
||||||
|
CodeObject* code = compile(source, filename, EXEC_MODE);
|
||||||
_exec(code, new_mod);
|
_exec(code, new_mod);
|
||||||
|
delete code; // leak if exception occurs
|
||||||
return new_mod;
|
return new_mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -556,13 +560,13 @@ i64 VM::py_hash(PyVar obj) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar locals) {
|
PyVar VM::__py_exec_internal(const CodeObject* code, PyVar globals, PyVar locals) {
|
||||||
Frame* frame = nullptr;
|
Frame* frame = nullptr;
|
||||||
if(!callstack.empty()) frame = &callstack.top();
|
if(!callstack.empty()) frame = &callstack.top();
|
||||||
|
|
||||||
// fast path
|
// fast path
|
||||||
if(frame && is_none(globals) && is_none(locals)) {
|
if(frame && is_none(globals) && is_none(locals)) {
|
||||||
return vm->_exec(code.get(), frame->_module, frame->_callable, frame->_locals);
|
return vm->_exec(code, frame->_module, frame->_callable, frame->_locals);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto _lock = gc_scope_lock(); // for safety
|
auto _lock = gc_scope_lock(); // for safety
|
||||||
@ -602,7 +606,7 @@ PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar local
|
|||||||
});
|
});
|
||||||
PyObject* _callable =
|
PyObject* _callable =
|
||||||
new_object<Function>(tp_function, __dynamic_func_decl, globals_obj, nullptr, locals_closure).get();
|
new_object<Function>(tp_function, __dynamic_func_decl, globals_obj, nullptr, locals_closure).get();
|
||||||
retval = vm->_exec(code.get(), globals_obj, _callable, vm->s_data._sp);
|
retval = vm->_exec(code, globals_obj, _callable, vm->s_data._sp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(globals_dict) {
|
if(globals_dict) {
|
||||||
@ -622,12 +626,12 @@ PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar local
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VM::py_exec(std::string_view source, PyVar globals, PyVar locals) {
|
void VM::py_exec(std::string_view source, PyVar globals, PyVar locals) {
|
||||||
CodeObject_ code = vm->compile(source, "<exec>", EXEC_MODE, true);
|
CodeObject* code = vm->compile(source, "<exec>", EXEC_MODE, true);
|
||||||
__py_exec_internal(code, globals, locals);
|
__py_exec_internal(code, globals, locals);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar VM::py_eval(std::string_view source, PyVar globals, PyVar locals) {
|
PyVar VM::py_eval(std::string_view source, PyVar globals, PyVar locals) {
|
||||||
CodeObject_ code = vm->compile(source, "<eval>", EVAL_MODE, true);
|
CodeObject* code = vm->compile(source, "<eval>", EVAL_MODE, true);
|
||||||
return __py_exec_internal(code, globals, locals);
|
return __py_exec_internal(code, globals, locals);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -738,7 +742,7 @@ PyObject* VM::new_module(Str name, Str package) {
|
|||||||
|
|
||||||
static std::string _opcode_argstr(VM* vm, int i, Bytecode byte, const CodeObject* co) {
|
static std::string _opcode_argstr(VM* vm, int i, Bytecode byte, const CodeObject* co) {
|
||||||
SStream ss;
|
SStream ss;
|
||||||
if(byte.is_forward_jump()) {
|
if(Bytecode__is_forward_jump(&byte)){
|
||||||
std::string argStr = std::to_string((int16_t)byte.arg);
|
std::string argStr = std::to_string((int16_t)byte.arg);
|
||||||
ss << (i64)(int16_t)byte.arg;
|
ss << (i64)(int16_t)byte.arg;
|
||||||
ss << " (to " << (i64)((int16_t)byte.arg + i) << ")";
|
ss << " (to " << (i64)((int16_t)byte.arg + i) << ")";
|
||||||
@ -775,7 +779,7 @@ static std::string _opcode_argstr(VM* vm, int i, Bytecode byte, const CodeObject
|
|||||||
return ss.str().str();
|
return ss.str().str();
|
||||||
}
|
}
|
||||||
|
|
||||||
Str VM::disassemble(CodeObject_ co) {
|
Str VM::disassemble(CodeObject* co) {
|
||||||
auto pad = [](const Str& s, const int n) {
|
auto pad = [](const Str& s, const int n) {
|
||||||
if(s.length() >= n) return s.slice(0, n);
|
if(s.length() >= n) return s.slice(0, n);
|
||||||
return s + std::string(n - s.length(), ' ');
|
return s + std::string(n - s.length(), ' ');
|
||||||
@ -784,7 +788,9 @@ Str VM::disassemble(CodeObject_ co) {
|
|||||||
vector<int> jumpTargets;
|
vector<int> jumpTargets;
|
||||||
for(int i = 0; i < co->codes.size(); i++) {
|
for(int i = 0; i < co->codes.size(); i++) {
|
||||||
Bytecode byte = co->codes[i];
|
Bytecode byte = co->codes[i];
|
||||||
if(byte.is_forward_jump()) { jumpTargets.push_back((int16_t)byte.arg + i); }
|
if(Bytecode__is_forward_jump(&byte)) {
|
||||||
|
jumpTargets.push_back((int16_t)byte.arg + i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
SStream ss;
|
SStream ss;
|
||||||
int prev_line = -1;
|
int prev_line = -1;
|
||||||
@ -808,7 +814,7 @@ Str VM::disassemble(CodeObject_ co) {
|
|||||||
std::string bc_name(OP_NAMES[byte.op]);
|
std::string bc_name(OP_NAMES[byte.op]);
|
||||||
if(co->lines[i].is_virtual) bc_name += '*';
|
if(co->lines[i].is_virtual) bc_name += '*';
|
||||||
ss << " " << pad(bc_name, 25) << " ";
|
ss << " " << pad(bc_name, 25) << " ";
|
||||||
std::string argStr = _opcode_argstr(this, i, byte, co.get());
|
std::string argStr = _opcode_argstr(this, i, byte, co);
|
||||||
ss << argStr;
|
ss << argStr;
|
||||||
if(i != co->codes.size() - 1) ss << '\n';
|
if(i != co->codes.size() - 1) ss << '\n';
|
||||||
}
|
}
|
||||||
@ -981,7 +987,7 @@ void VM::__unpack_as_dict(ArgsView args, Dict& dict) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VM::__prepare_py_call(PyVar* buffer, ArgsView args, ArgsView kwargs, const FuncDecl_& decl) {
|
void VM::__prepare_py_call(PyVar* buffer, ArgsView args, ArgsView kwargs, const FuncDecl_& decl) {
|
||||||
const CodeObject* co = decl->code.get();
|
const CodeObject* co = decl->code;
|
||||||
int decl_argc = decl->args.size();
|
int decl_argc = decl->args.size();
|
||||||
|
|
||||||
if(args.size() < decl_argc) {
|
if(args.size() < decl_argc) {
|
||||||
@ -994,8 +1000,9 @@ void VM::__prepare_py_call(PyVar* buffer, ArgsView args, ArgsView kwargs, const
|
|||||||
for(int index: decl->args)
|
for(int index: decl->args)
|
||||||
buffer[index] = args[i++];
|
buffer[index] = args[i++];
|
||||||
// prepare kwdefaults
|
// prepare kwdefaults
|
||||||
for(auto& kv: decl->kwargs)
|
c11_vector__foreach(FuncDecl::KwArg, &decl->kwargs, kv) {
|
||||||
buffer[kv.index] = kv.value;
|
buffer[kv->index] = kv->value;
|
||||||
|
}
|
||||||
|
|
||||||
// handle *args
|
// handle *args
|
||||||
if(decl->starred_arg != -1) {
|
if(decl->starred_arg != -1) {
|
||||||
@ -1004,9 +1011,9 @@ void VM::__prepare_py_call(PyVar* buffer, ArgsView args, ArgsView kwargs, const
|
|||||||
i += vargs.size();
|
i += vargs.size();
|
||||||
} else {
|
} else {
|
||||||
// kwdefaults override
|
// kwdefaults override
|
||||||
for(auto& kv: decl->kwargs) {
|
c11_vector__foreach(FuncDecl::KwArg, &decl->kwargs, kv) {
|
||||||
if(i >= args.size()) break;
|
if(i >= args.size()) break;
|
||||||
buffer[kv.index] = args[i++];
|
buffer[kv->index] = args[i++];
|
||||||
}
|
}
|
||||||
if(i < args.size()) TypeError(_S("too many arguments", " (", decl->code->name, ')'));
|
if(i < args.size()) TypeError(_S("too many arguments", " (", decl->code->name, ')'));
|
||||||
}
|
}
|
||||||
@ -1067,17 +1074,17 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
|||||||
if(s_data.is_overflow()) StackOverflowError();
|
if(s_data.is_overflow()) StackOverflowError();
|
||||||
|
|
||||||
const Function& fn = PK_OBJ_GET(Function, callable);
|
const Function& fn = PK_OBJ_GET(Function, callable);
|
||||||
const CodeObject* co = fn.decl->code.get();
|
const CodeObject* co = fn.decl->code;
|
||||||
|
|
||||||
switch(fn.decl->type) {
|
switch(fn.decl->type) {
|
||||||
case FuncType::NORMAL:
|
case FuncType_NORMAL:
|
||||||
__prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl);
|
__prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl);
|
||||||
// copy buffer back to stack
|
// copy buffer back to stack
|
||||||
s_data.reset(_base + co->nlocals);
|
s_data.reset(_base + co->nlocals);
|
||||||
for(int j = 0; j < co->nlocals; j++)
|
for(int j = 0; j < co->nlocals; j++)
|
||||||
_base[j] = __vectorcall_buffer[j];
|
_base[j] = __vectorcall_buffer[j];
|
||||||
break;
|
break;
|
||||||
case FuncType::SIMPLE:
|
case FuncType_SIMPLE:
|
||||||
if(args.size() != fn.decl->args.size())
|
if(args.size() != fn.decl->args.size())
|
||||||
TypeError(_S(co->name,
|
TypeError(_S(co->name,
|
||||||
"() takes ",
|
"() takes ",
|
||||||
@ -1092,7 +1099,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
|||||||
// initialize local variables to PY_NULL
|
// initialize local variables to PY_NULL
|
||||||
std::memset(p1, 0, (char*)s_data._sp - (char*)p1);
|
std::memset(p1, 0, (char*)s_data._sp - (char*)p1);
|
||||||
break;
|
break;
|
||||||
case FuncType::EMPTY:
|
case FuncType_EMPTY:
|
||||||
if(args.size() != fn.decl->args.size())
|
if(args.size() != fn.decl->args.size())
|
||||||
TypeError(_S(co->name,
|
TypeError(_S(co->name,
|
||||||
"() takes ",
|
"() takes ",
|
||||||
@ -1103,7 +1110,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
|||||||
if(!kwargs.empty()) TypeError(_S(co->name, "() takes no keyword arguments"));
|
if(!kwargs.empty()) TypeError(_S(co->name, "() takes no keyword arguments"));
|
||||||
s_data.reset(p0);
|
s_data.reset(p0);
|
||||||
return None;
|
return None;
|
||||||
case FuncType::GENERATOR:
|
case FuncType_GENERATOR:
|
||||||
__prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl);
|
__prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl);
|
||||||
s_data.reset(p0);
|
s_data.reset(p0);
|
||||||
callstack.emplace(nullptr, co, fn._module, callable.get(), nullptr);
|
callstack.emplace(nullptr, co, fn._module, callable.get(), nullptr);
|
||||||
@ -1360,9 +1367,9 @@ void VM::setattr(PyVar obj, StrName name, PyVar value) {
|
|||||||
PyObject* VM::bind_func(PyObject* obj, StrName name, int argc, NativeFuncC fn, any userdata, BindType bt) {
|
PyObject* VM::bind_func(PyObject* obj, StrName name, int argc, NativeFuncC fn, any userdata, BindType bt) {
|
||||||
PyObject* nf = new_object<NativeFunc>(tp_native_func, fn, argc, std::move(userdata)).get();
|
PyObject* nf = new_object<NativeFunc>(tp_native_func, fn, argc, std::move(userdata)).get();
|
||||||
switch(bt) {
|
switch(bt) {
|
||||||
case BindType::DEFAULT: break;
|
case BindType_FUNCTION: break;
|
||||||
case BindType::STATICMETHOD: nf = new_object<StaticMethod>(tp_staticmethod, nf).get(); break;
|
case BindType_STATICMETHOD: nf = new_object<StaticMethod>(tp_staticmethod, nf).get(); break;
|
||||||
case BindType::CLASSMETHOD: nf = new_object<ClassMethod>(tp_classmethod, nf).get(); break;
|
case BindType_CLASSMETHOD: nf = new_object<ClassMethod>(tp_classmethod, nf).get(); break;
|
||||||
}
|
}
|
||||||
if(obj != nullptr) obj->attr().set(name, nf);
|
if(obj != nullptr) obj->attr().set(name, nf);
|
||||||
return nf;
|
return nf;
|
||||||
@ -1377,17 +1384,17 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native
|
|||||||
int length = snprintf(buffer, sizeof(buffer), "def %s : pass", sig);
|
int length = snprintf(buffer, sizeof(buffer), "def %s : pass", sig);
|
||||||
std::string_view source(buffer, length);
|
std::string_view source(buffer, length);
|
||||||
// fn(a, b, *c, d=1) -> None
|
// fn(a, b, *c, d=1) -> None
|
||||||
CodeObject_ co = compile(source, "<bind>", EXEC_MODE);
|
CodeObject* code = compile(source, "<bind>", EXEC_MODE);
|
||||||
assert(co->func_decls.size() == 1);
|
assert(code->func_decls.size() == 1);
|
||||||
|
FuncDecl_ decl = code->func_decls[0];
|
||||||
FuncDecl_ decl = co->func_decls[0];
|
delete code; // may leak if exception occurs
|
||||||
decl->docstring = docstring;
|
decl->docstring = docstring;
|
||||||
PyObject* f_obj = new_object<NativeFunc>(tp_native_func, fn, decl, std::move(userdata)).get();
|
PyObject* f_obj = new_object<NativeFunc>(tp_native_func, fn, decl, std::move(userdata)).get();
|
||||||
|
|
||||||
switch(bt) {
|
switch(bt) {
|
||||||
case BindType::STATICMETHOD: f_obj = new_object<StaticMethod>(tp_staticmethod, f_obj).get(); break;
|
case BindType_STATICMETHOD: f_obj = new_object<StaticMethod>(tp_staticmethod, f_obj).get(); break;
|
||||||
case BindType::CLASSMETHOD: f_obj = new_object<ClassMethod>(tp_classmethod, f_obj).get(); break;
|
case BindType_CLASSMETHOD: f_obj = new_object<ClassMethod>(tp_classmethod, f_obj).get(); break;
|
||||||
case BindType::DEFAULT: break;
|
case BindType_FUNCTION: break;
|
||||||
}
|
}
|
||||||
if(obj != nullptr) obj->attr().set(decl->code->name, f_obj);
|
if(obj != nullptr) obj->attr().set(decl->code->name, f_obj);
|
||||||
return f_obj;
|
return f_obj;
|
||||||
@ -1793,13 +1800,15 @@ void VM::__breakpoint() {
|
|||||||
std::string arg = line.substr(space + 1);
|
std::string arg = line.substr(space + 1);
|
||||||
if(arg.empty()) continue; // ignore empty command
|
if(arg.empty()) continue; // ignore empty command
|
||||||
if(cmd == "p" || cmd == "print") {
|
if(cmd == "p" || cmd == "print") {
|
||||||
CodeObject_ code = compile(arg, "<stdin>", EVAL_MODE, true);
|
CodeObject* code = compile(arg, "<stdin>", EVAL_MODE, true);
|
||||||
PyVar retval = vm->_exec(code.get(), frame_0->_module, frame_0->_callable, frame_0->_locals);
|
PyVar retval = vm->_exec(code, frame_0->_module, frame_0->_callable, frame_0->_locals);
|
||||||
|
delete code;
|
||||||
stdout_write(vm->py_repr(retval));
|
stdout_write(vm->py_repr(retval));
|
||||||
stdout_write("\n");
|
stdout_write("\n");
|
||||||
} else if(cmd == "!") {
|
} else if(cmd == "!") {
|
||||||
CodeObject_ code = compile(arg, "<stdin>", EXEC_MODE, true);
|
CodeObject* code = compile(arg, "<stdin>", EXEC_MODE, true);
|
||||||
vm->_exec(code.get(), frame_0->_module, frame_0->_callable, frame_0->_locals);
|
vm->_exec(code, frame_0->_module, frame_0->_callable, frame_0->_locals);
|
||||||
|
delete code;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1828,8 +1837,9 @@ void NativeFunc::_gc_mark(VM* vm) const {
|
|||||||
|
|
||||||
void FuncDecl::_gc_mark(VM* vm) const {
|
void FuncDecl::_gc_mark(VM* vm) const {
|
||||||
code->_gc_mark(vm);
|
code->_gc_mark(vm);
|
||||||
for(int i = 0; i < kwargs.size(); i++)
|
c11_vector__foreach(FuncDecl::KwArg, &kwargs, kv) {
|
||||||
vm->obj_gc_mark(kwargs[i].value);
|
vm->obj_gc_mark(kv->value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void List::_gc_mark(VM* vm) const {
|
void List::_gc_mark(VM* vm) const {
|
||||||
|
|||||||
@ -152,7 +152,7 @@ void Vec2::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
return VAR(Tuple(VAR(ret), VAR(current_velocity_)));
|
return VAR(Tuple(VAR(ret), VAR(current_velocity_)));
|
||||||
},
|
},
|
||||||
{},
|
{},
|
||||||
BindType::STATICMETHOD);
|
BindType_STATICMETHOD);
|
||||||
|
|
||||||
// @staticmethod
|
// @staticmethod
|
||||||
vm->bind(
|
vm->bind(
|
||||||
@ -168,7 +168,7 @@ void Vec2::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
return VAR(val);
|
return VAR(val);
|
||||||
},
|
},
|
||||||
{},
|
{},
|
||||||
BindType::STATICMETHOD);
|
BindType_STATICMETHOD);
|
||||||
|
|
||||||
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) -> Str {
|
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) -> Str {
|
||||||
Vec2 self = _CAST(Vec2, obj);
|
Vec2 self = _CAST(Vec2, obj);
|
||||||
@ -452,7 +452,7 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
return vm->new_user_object<Mat3x3>(Mat3x3::zeros());
|
return vm->new_user_object<Mat3x3>(Mat3x3::zeros());
|
||||||
},
|
},
|
||||||
{},
|
{},
|
||||||
BindType::STATICMETHOD);
|
BindType_STATICMETHOD);
|
||||||
|
|
||||||
// @staticmethod
|
// @staticmethod
|
||||||
vm->bind_func(
|
vm->bind_func(
|
||||||
@ -463,7 +463,7 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
return vm->new_user_object<Mat3x3>(Mat3x3::ones());
|
return vm->new_user_object<Mat3x3>(Mat3x3::ones());
|
||||||
},
|
},
|
||||||
{},
|
{},
|
||||||
BindType::STATICMETHOD);
|
BindType_STATICMETHOD);
|
||||||
|
|
||||||
// @staticmethod
|
// @staticmethod
|
||||||
vm->bind_func(
|
vm->bind_func(
|
||||||
@ -474,7 +474,7 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
return vm->new_user_object<Mat3x3>(Mat3x3::identity());
|
return vm->new_user_object<Mat3x3>(Mat3x3::identity());
|
||||||
},
|
},
|
||||||
{},
|
{},
|
||||||
BindType::STATICMETHOD);
|
BindType_STATICMETHOD);
|
||||||
|
|
||||||
/*************** affine transformations ***************/
|
/*************** affine transformations ***************/
|
||||||
// @staticmethod
|
// @staticmethod
|
||||||
@ -488,7 +488,7 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
return vm->new_user_object<Mat3x3>(Mat3x3::trs(t, r, s));
|
return vm->new_user_object<Mat3x3>(Mat3x3::trs(t, r, s));
|
||||||
},
|
},
|
||||||
{},
|
{},
|
||||||
BindType::STATICMETHOD);
|
BindType_STATICMETHOD);
|
||||||
|
|
||||||
vm->bind(type, "copy_trs_(self, t: vec2, r: float, s: vec2)", [](VM* vm, ArgsView args) {
|
vm->bind(type, "copy_trs_(self, t: vec2, r: float, s: vec2)", [](VM* vm, ArgsView args) {
|
||||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||||
|
|||||||
@ -106,8 +106,10 @@ void add_module_json(VM* vm) {
|
|||||||
} else {
|
} else {
|
||||||
sv = CAST(Str&, args[0]).sv();
|
sv = CAST(Str&, args[0]).sv();
|
||||||
}
|
}
|
||||||
CodeObject_ code = vm->compile(sv, "<json>", JSON_MODE);
|
CodeObject* code = vm->compile(sv, "<json>", JSON_MODE);
|
||||||
return vm->_exec(code, vm->callstack.top()._module);
|
PyVar retval = vm->_exec(code, vm->callstack.top()._module);
|
||||||
|
delete code; // leak on error
|
||||||
|
return retval;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(mod, "dumps", 1, [](VM* vm, ArgsView args) {
|
vm->bind_func(mod, "dumps", 1, [](VM* vm, ArgsView args) {
|
||||||
@ -224,16 +226,19 @@ void add_module_dis(VM* vm) {
|
|||||||
PyObject* mod = vm->new_module("dis");
|
PyObject* mod = vm->new_module("dis");
|
||||||
|
|
||||||
vm->bind_func(mod, "dis", 1, [](VM* vm, ArgsView args) {
|
vm->bind_func(mod, "dis", 1, [](VM* vm, ArgsView args) {
|
||||||
CodeObject_ code;
|
CodeObject* code;
|
||||||
|
bool need_delete = false;
|
||||||
PyVar obj = args[0];
|
PyVar obj = args[0];
|
||||||
if(is_type(obj, vm->tp_str)) {
|
if(is_type(obj, vm->tp_str)) {
|
||||||
const Str& source = CAST(Str, obj);
|
const Str& source = CAST(Str, obj);
|
||||||
code = vm->compile(source, "<dis>", EXEC_MODE);
|
code = vm->compile(source, "<dis>", EXEC_MODE);
|
||||||
|
need_delete = true;
|
||||||
}
|
}
|
||||||
PyVar f = obj;
|
PyVar f = obj;
|
||||||
if(is_type(f, vm->tp_bound_method)) f = CAST(BoundMethod, obj).func;
|
if(is_type(f, vm->tp_bound_method)) f = CAST(BoundMethod, obj).func;
|
||||||
code = CAST(Function&, f).decl->code;
|
code = CAST(Function&, f).decl->code;
|
||||||
vm->stdout_write(vm->disassemble(code));
|
vm->stdout_write(vm->disassemble(code));
|
||||||
|
if(need_delete) delete code;
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -245,8 +250,9 @@ void add_module_gc(VM* vm) {
|
|||||||
|
|
||||||
void add_module_enum(VM* vm) {
|
void add_module_enum(VM* vm) {
|
||||||
PyObject* mod = vm->new_module("enum");
|
PyObject* mod = vm->new_module("enum");
|
||||||
CodeObject_ code = vm->compile(kPythonLibs__enum, "enum.py", EXEC_MODE);
|
CodeObject* code = vm->compile(kPythonLibs__enum, "enum.py", EXEC_MODE);
|
||||||
vm->_exec(code, mod);
|
vm->_exec(code, mod);
|
||||||
|
delete code; // leak on error
|
||||||
PyVar Enum = mod->attr("Enum");
|
PyVar Enum = mod->attr("Enum");
|
||||||
vm->_all_types[PK_OBJ_GET(Type, Enum)].on_end_subclass = [](VM* vm, PyTypeInfo* new_ti) {
|
vm->_all_types[PK_OBJ_GET(Type, Enum)].on_end_subclass = [](VM* vm, PyTypeInfo* new_ti) {
|
||||||
new_ti->subclass_enabled = false; // Enum class cannot be subclassed twice
|
new_ti->subclass_enabled = false; // Enum class cannot be subclassed twice
|
||||||
|
|||||||
13
src/objects/codeobject.c
Normal file
13
src/objects/codeobject.c
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#include "pocketpy/objects/codeobject.h"
|
||||||
|
#include "pocketpy/common/utils.h"
|
||||||
|
|
||||||
|
void Bytecode__set_signed_arg(Bytecode* self, int arg) {
|
||||||
|
if(arg < INT16_MIN || arg > INT16_MAX) {
|
||||||
|
PK_FATAL_ERROR("set_signed_arg: %d is out of range", arg);
|
||||||
|
}
|
||||||
|
self->arg = (int16_t)arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bytecode__is_forward_jump(const Bytecode* self) {
|
||||||
|
return self->op >= OP_JUMP_FORWARD && self->op <= OP_LOOP_BREAK;
|
||||||
|
}
|
||||||
@ -1691,13 +1691,16 @@ void VM::__post_init_builtin_types() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// initialize dummy func_decl for exec/eval
|
// initialize dummy func_decl for exec/eval
|
||||||
CodeObject_ dynamic_co = compile("def _(): pass", "<dynamic>", EXEC_MODE);
|
CodeObject* code = compile("def _(): pass", "<dynamic>", EXEC_MODE);
|
||||||
__dynamic_func_decl = dynamic_co->func_decls[0];
|
__dynamic_func_decl = code->func_decls[0];
|
||||||
|
delete code; // may leak on error
|
||||||
// initialize builtins
|
// initialize builtins
|
||||||
CodeObject_ code = compile(kPythonLibs_builtins, "<builtins>", EXEC_MODE);
|
code = compile(kPythonLibs_builtins, "<builtins>", EXEC_MODE);
|
||||||
this->_exec(code, this->builtins);
|
this->_exec(code, this->builtins);
|
||||||
|
delete code; // may leak on error
|
||||||
code = compile(kPythonLibs__set, "<set>", EXEC_MODE);
|
code = compile(kPythonLibs__set, "<set>", EXEC_MODE);
|
||||||
this->_exec(code, this->builtins);
|
this->_exec(code, this->builtins);
|
||||||
|
delete code; // may leak on error
|
||||||
} catch(TopLevelException e) {
|
} catch(TopLevelException e) {
|
||||||
std::cerr << e.summary() << std::endl;
|
std::cerr << e.summary() << std::endl;
|
||||||
std::cerr << "failed to load builtins module!!" << std::endl;
|
std::cerr << "failed to load builtins module!!" << std::endl;
|
||||||
@ -1723,9 +1726,9 @@ void VM::__post_init_builtin_types() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
CodeObject_ VM::compile(std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope) {
|
CodeObject* VM::compile(std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope) {
|
||||||
Compiler compiler(this, source, filename, mode, unknown_global_scope);
|
Compiler compiler(this, source, filename, mode, unknown_global_scope);
|
||||||
CodeObject_ code;
|
CodeObject* code;
|
||||||
Error* err = compiler.compile(&code);
|
Error* err = compiler.compile(&code);
|
||||||
if(err) __compile_error(err);
|
if(err) __compile_error(err);
|
||||||
return code;
|
return code;
|
||||||
|
|||||||
@ -60,8 +60,9 @@ bool pkpy_exec(pkpy_vm* vm_handle, const char* source) {
|
|||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PyVar res;
|
PyVar res;
|
||||||
PK_PROTECTED(
|
PK_PROTECTED(
|
||||||
CodeObject_ code = vm->compile(source, "main.py", EXEC_MODE);
|
CodeObject* code = vm->compile(source, "main.py", EXEC_MODE);
|
||||||
res = vm->_exec(code, vm->_main);
|
res = vm->_exec(code, vm->_main);
|
||||||
|
delete code; // TODO: _exec may raise, so code may leak
|
||||||
)
|
)
|
||||||
return res != nullptr;
|
return res != nullptr;
|
||||||
}
|
}
|
||||||
@ -76,8 +77,9 @@ bool pkpy_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, i
|
|||||||
}else{
|
}else{
|
||||||
mod = vm->_modules[module].get(); // may raise
|
mod = vm->_modules[module].get(); // may raise
|
||||||
}
|
}
|
||||||
CodeObject_ code = vm->compile(source, filename, (CompileMode)mode);
|
CodeObject* code = vm->compile(source, filename, (CompileMode)mode);
|
||||||
res = vm->_exec(code, mod);
|
res = vm->_exec(code, mod);
|
||||||
|
delete code; // TODO: _exec may raise, so code may leak
|
||||||
)
|
)
|
||||||
return res != nullptr;
|
return res != nullptr;
|
||||||
}
|
}
|
||||||
@ -417,9 +419,10 @@ bool pkpy_eval(pkpy_vm* vm_handle, const char* source) {
|
|||||||
VM* vm = (VM*)vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_PROTECTED(
|
PK_PROTECTED(
|
||||||
CodeObject_ co = vm->compile(source, "<eval>", EVAL_MODE);
|
CodeObject* co = vm->compile(source, "<eval>", EVAL_MODE);
|
||||||
PyVar ret = vm->_exec(co, vm->_main);
|
PyVar ret = vm->_exec(co, vm->_main);
|
||||||
vm->s_data.push(ret);
|
vm->s_data.push(ret);
|
||||||
|
delete co; // TODO: _exec may raise, so code may leak
|
||||||
)
|
)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user