This commit is contained in:
blueloveTH 2024-06-23 01:42:29 +08:00
parent 28c3b35d39
commit 8b8552d54b
21 changed files with 598 additions and 451 deletions

View File

@ -5,7 +5,7 @@ python prebuild.py
SRC_C=$(find src/ -name "*.c") SRC_C=$(find src/ -name "*.c")
SRC_CPP=$(find src/ -name "*.cpp") SRC_CPP=$(find src/ -name "*.cpp")
COMMON_FLAGS="-Iinclude -O0 -Wfatal-errors -g -DDEBUG -DPK_ENABLE_OS=1" COMMON_FLAGS="-Iinclude -O0 -Wfatal-errors -g -DDEBUG -DPK_ENABLE_OS=1" # -fsanitize=address,leak,undefined"
FLAGS_C="-std=c11 $COMMON_FLAGS" FLAGS_C="-std=c11 $COMMON_FLAGS"
FLAGS_CPP="-std=c++17 -stdlib=libc++ -frtti $COMMON_FLAGS" FLAGS_CPP="-std=c++17 -stdlib=libc++ -frtti $COMMON_FLAGS"

View File

@ -10,11 +10,11 @@
extern "C" { extern "C" {
#endif #endif
typedef struct pkpy_SStream { typedef struct pk_SStream {
c11_vector data; c11_vector data;
} pkpy_SStream; } pk_SStream;
typedef struct pkpy_AnyStr { typedef struct pk_AnyStr {
int type; int type;
union { union {
int _int; int _int;
@ -27,59 +27,62 @@ typedef struct pkpy_AnyStr {
const char* _cstr; const char* _cstr;
void* _ptr; void* _ptr;
}; };
} pkpy_AnyStr; } pk_AnyStr;
PK_INLINE pkpy_AnyStr pkpy_AnyStr__int(int x) { pkpy_AnyStr s; s.type = 1; s._int = x; return s; } PK_INLINE pk_AnyStr pk_AnyStr__int(int x) { pk_AnyStr s; s.type = 1; s._int = x; return s; }
PK_INLINE pkpy_AnyStr pkpy_AnyStr__i64(int64_t x) { pkpy_AnyStr s; s.type = 2; s._i64 = x; return s; } PK_INLINE pk_AnyStr pk_AnyStr__i64(int64_t x) { pk_AnyStr s; s.type = 2; s._i64 = x; return s; }
PK_INLINE pkpy_AnyStr pkpy_AnyStr__float(float x) { pkpy_AnyStr s; s.type = 3; s._float = x; return s; } PK_INLINE pk_AnyStr pk_AnyStr__float(float x) { pk_AnyStr s; s.type = 3; s._float = x; return s; }
PK_INLINE pkpy_AnyStr pkpy_AnyStr__double(double x) { pkpy_AnyStr s; s.type = 4; s._double = x; return s; } PK_INLINE pk_AnyStr pk_AnyStr__double(double x) { pk_AnyStr s; s.type = 4; s._double = x; return s; }
PK_INLINE pkpy_AnyStr pkpy_AnyStr__char(char x) { pkpy_AnyStr s; s.type = 5; s._char = x; return s; } PK_INLINE pk_AnyStr pk_AnyStr__char(char x) { pk_AnyStr s; s.type = 5; s._char = x; return s; }
PK_INLINE pkpy_AnyStr pkpy_AnyStr__str(const pkpy_Str* x) { pkpy_AnyStr s; s.type = 6; s._str = x; return s; } PK_INLINE pk_AnyStr pk_AnyStr__str(const pkpy_Str* x) { pk_AnyStr s; s.type = 6; s._str = x; return s; }
PK_INLINE pkpy_AnyStr pkpy_AnyStr__sv(c11_string x) { pkpy_AnyStr s; s.type = 7; s._sv = x; return s; } PK_INLINE pk_AnyStr pk_AnyStr__sv(c11_string x) { pk_AnyStr s; s.type = 7; s._sv = x; return s; }
PK_INLINE pkpy_AnyStr pkpy_AnyStr__cstr(const char* x) { pkpy_AnyStr s; s.type = 8; s._cstr = x; return s; } PK_INLINE pk_AnyStr pk_AnyStr__cstr(const char* x) { pk_AnyStr s; s.type = 8; s._cstr = x; return s; }
PK_INLINE pkpy_AnyStr pkpy_AnyStr__ptr(void* x) { pkpy_AnyStr s; s.type = 9; s._ptr = x; return s; } PK_INLINE pk_AnyStr pk_AnyStr__ptr(void* x) { pk_AnyStr s; s.type = 9; s._ptr = x; return s; }
void pkpy_SStream__ctor(pkpy_SStream* self); void pk_SStream__ctor(pk_SStream* self);
void pkpy_SStream__ctor2(pkpy_SStream* self, int capacity); void pk_SStream__ctor2(pk_SStream* self, int capacity);
void pkpy_SStream__dtor(pkpy_SStream* self); void pk_SStream__dtor(pk_SStream* self);
void pkpy_SStream__write_int(pkpy_SStream* self, int); void pk_SStream__write_int(pk_SStream* self, int);
void pkpy_SStream__write_i64(pkpy_SStream* self, int64_t); void pk_SStream__write_i64(pk_SStream* self, int64_t);
void pkpy_SStream__write_float(pkpy_SStream* self, float, int precision); void pk_SStream__write_float(pk_SStream* self, float, int precision);
void pkpy_SStream__write_double(pkpy_SStream* self, double, int precision); void pk_SStream__write_double(pk_SStream* self, double, int precision);
void pkpy_SStream__write_char(pkpy_SStream* self, char); void pk_SStream__write_char(pk_SStream* self, char);
void pkpy_SStream__write_Str(pkpy_SStream* self, const pkpy_Str*); void pk_SStream__write_Str(pk_SStream* self, const pkpy_Str*);
void pkpy_SStream__write_sv(pkpy_SStream* self, c11_string); void pk_SStream__write_sv(pk_SStream* self, c11_string);
void pkpy_SStream__write_cstr(pkpy_SStream* self, const char*); void pk_SStream__write_cstr(pk_SStream* self, const char*);
void pkpy_SStream__write_cstrn(pkpy_SStream* self, const char*, int); void pk_SStream__write_cstrn(pk_SStream* self, const char*, int);
void pkpy_SStream__write_hex(pkpy_SStream* self, unsigned char, bool non_zero); void pk_SStream__write_hex(pk_SStream* self, unsigned char, bool non_zero);
void pkpy_SStream__write_ptr(pkpy_SStream* self, void*); void pk_SStream__write_ptr(pk_SStream* self, void*);
void pkpy_SStream__write_any(pkpy_SStream* self, const char* fmt, const pkpy_AnyStr* args, int n);
void pk_SStream__write_any(pk_SStream* self, const char* fmt, const pk_AnyStr* args, int n);
const char* pk_format_any(const char* fmt, const pk_AnyStr* args, int n);
// Submit the stream and return the final string. The stream becomes invalid after this call // Submit the stream and return the final string. The stream becomes invalid after this call
pkpy_Str pkpy_SStream__submit(pkpy_SStream* self); pkpy_Str pk_SStream__submit(pk_SStream* self);
#define pkpy__anystr(x) _Generic((x), \ #define pk__anystr(x) _Generic((x), \
int: pkpy_AnyStr__int, \ int: pk_AnyStr__int, \
int64_t: pkpy_AnyStr__i64, \ int64_t: pk_AnyStr__i64, \
float: pkpy_AnyStr__float, \ float: pk_AnyStr__float, \
double: pkpy_AnyStr__double, \ double: pk_AnyStr__double, \
char: pkpy_AnyStr__char, \ char: pk_AnyStr__char, \
const pkpy_Str*: pkpy_AnyStr__str, \ const pkpy_Str*: pk_AnyStr__str, \
c11_string: pkpy_AnyStr__sv, \ c11_string: pk_AnyStr__sv, \
const char*: pkpy_AnyStr__cstr, \ const char*: pk_AnyStr__cstr, \
void*: pkpy_AnyStr__ptr \ void*: pk_AnyStr__ptr \
)(x) )(x)
#define pkpy__anystr_list_1(a) (pkpy_AnyStr[]){pkpy__anystr(a)}, 1 #define pk__anystr_list_1(a) (pk_AnyStr[]){pk__anystr(a)}, 1
#define pkpy__anystr_list_2(a, b) (pkpy_AnyStr[]){pkpy__anystr(a), pkpy__anystr(b)}, 2 #define pk__anystr_list_2(a, b) (pk_AnyStr[]){pk__anystr(a), pk__anystr(b)}, 2
#define pkpy__anystr_list_3(a, b, c) (pkpy_AnyStr[]){pkpy__anystr(a), pkpy__anystr(b), pkpy__anystr(c)}, 3 #define pk__anystr_list_3(a, b, c) (pk_AnyStr[]){pk__anystr(a), pk__anystr(b), pk__anystr(c)}, 3
#define pkpy__anystr_list_4(a, b, c, d) (pkpy_AnyStr[]){pkpy__anystr(a), pkpy__anystr(b), pkpy__anystr(c), pkpy__anystr(d)}, 4 #define pk__anystr_list_4(a, b, c, d) (pk_AnyStr[]){pk__anystr(a), pk__anystr(b), pk__anystr(c), pk__anystr(d)}, 4
#define pkpy__anystr_list_dispatcher(...) PK_NARGS_SEQ(__VA_ARGS__, pkpy__anystr_list_4, pkpy__anystr_list_3, pkpy__anystr_list_2, pkpy__anystr_list_1, 0) #define pk__anystr_list_dispatcher(...) PK_NARGS_SEQ(__VA_ARGS__, pk__anystr_list_4, pk__anystr_list_3, pk__anystr_list_2, pk__anystr_list_1, 0)
#define pkpy__anystr_list(...) pkpy__anystr_list_dispatcher(__VA_ARGS__)(__VA_ARGS__) #define pk__anystr_list(...) pk__anystr_list_dispatcher(__VA_ARGS__)(__VA_ARGS__)
#define pkpy_SStream__write(self, fmt, ...) pkpy_SStream__write_any(self, fmt, pkpy__anystr_list(__VA_ARGS__)) #define pk_SStream__write(self, fmt, ...) pk_SStream__write_any(self, fmt, pk__anystr_list(__VA_ARGS__))
#define pk_format(fmt, ...) pk_format_any(fmt, pk__anystr_list(__VA_ARGS__))
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -288,7 +288,7 @@ struct StrName {
} }
}; };
struct SStream: pkpy_SStream { struct SStream: pk_SStream {
PK_ALWAYS_PASS_BY_POINTER(SStream) PK_ALWAYS_PASS_BY_POINTER(SStream)
int _precision = -1; int _precision = -1;
@ -298,85 +298,85 @@ struct SStream: pkpy_SStream {
void setprecision(int precision) { _precision = precision; } void setprecision(int precision) { _precision = precision; }
SStream() { SStream() {
pkpy_SStream__ctor(this); pk_SStream__ctor(this);
} }
SStream(int guess_size) { c11_vector__reserve(&data, guess_size); } SStream(int guess_size) { c11_vector__reserve(&data, guess_size); }
~SStream() { ~SStream() {
// in case of error // in case of error
if(!_submited) pkpy_SStream__dtor(this); if(!_submited) pk_SStream__dtor(this);
} }
Str str(){ Str str(){
assert(!_submited); assert(!_submited);
_submited = true; _submited = true;
return pkpy_SStream__submit(this); return pk_SStream__submit(this);
} }
SStream& operator<< (const Str& val){ SStream& operator<< (const Str& val){
pkpy_SStream__write_Str(this, &val); pk_SStream__write_Str(this, &val);
return *this; return *this;
} }
SStream& operator<< (const char* val){ SStream& operator<< (const char* val){
pkpy_SStream__write_cstr(this, val); pk_SStream__write_cstr(this, val);
return *this; return *this;
} }
SStream& operator<< (int val){ SStream& operator<< (int val){
pkpy_SStream__write_int(this, val); pk_SStream__write_int(this, val);
return *this; return *this;
} }
SStream& operator<< (size_t val){ SStream& operator<< (size_t val){
// size_t could overflow int64, but nevermind... // size_t could overflow int64, but nevermind...
pkpy_SStream__write_i64(this, val); pk_SStream__write_i64(this, val);
return *this; return *this;
} }
SStream& operator<< (i64 val){ SStream& operator<< (i64 val){
pkpy_SStream__write_i64(this, val); pk_SStream__write_i64(this, val);
return *this; return *this;
} }
SStream& operator<< (f64 val){ SStream& operator<< (f64 val){
pkpy_SStream__write_double(this, val, _precision); pk_SStream__write_double(this, val, _precision);
return *this; return *this;
} }
SStream& operator<< (const std::string& val){ SStream& operator<< (const std::string& val){
pkpy_SStream__write_cstrn(this, val.data(), val.size()); pk_SStream__write_cstrn(this, val.data(), val.size());
return *this; return *this;
} }
SStream& operator<< (std::string_view val){ SStream& operator<< (std::string_view val){
pkpy_SStream__write_cstrn(this, val.data(), val.size()); pk_SStream__write_cstrn(this, val.data(), val.size());
return *this; return *this;
} }
SStream& operator<< (c11_string val){ SStream& operator<< (c11_string val){
pkpy_SStream__write_cstrn(this, val.data, val.size); pk_SStream__write_cstrn(this, val.data, val.size);
return *this; return *this;
} }
SStream& operator<< (char val){ SStream& operator<< (char val){
pkpy_SStream__write_char(this, val); pk_SStream__write_char(this, val);
return *this; return *this;
} }
SStream& operator<< (StrName name){ SStream& operator<< (StrName name){
std::string_view sv = name.sv(); std::string_view sv = name.sv();
pkpy_SStream__write_cstrn(this, sv.data(), sv.size()); pk_SStream__write_cstrn(this, sv.data(), sv.size());
return *this; return *this;
} }
void write_hex(unsigned char val, bool non_zero = false){ void write_hex(unsigned char val, bool non_zero = false){
pkpy_SStream__write_hex(this, val, non_zero); pk_SStream__write_hex(this, val, non_zero);
} }
void write_ptr(void* p){ void write_ptr(void* p){
pkpy_SStream__write_ptr(this, p); pk_SStream__write_ptr(this, p);
} }
}; };

View File

@ -55,7 +55,7 @@ struct Compiler {
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(c11_string name, int* out_index) noexcept;
static void init_pratt_rules() noexcept; static void init_pratt_rules() noexcept;
@ -118,7 +118,7 @@ struct Compiler {
[[nodiscard]] Error* try_compile_assignment(bool* is_assign) noexcept; [[nodiscard]] Error* try_compile_assignment(bool* is_assign) noexcept;
[[nodiscard]] Error* compile_stmt() noexcept; [[nodiscard]] Error* compile_stmt() noexcept;
[[nodiscard]] Error* consume_type_hints() noexcept; [[nodiscard]] Error* consume_type_hints() noexcept;
[[nodiscard]] Error* _compile_f_args(FuncDecl_ decl, bool enable_type_hints) noexcept; [[nodiscard]] Error* _compile_f_args(FuncDecl* decl, bool enable_type_hints) noexcept;
[[nodiscard]] Error* compile_function(int decorators = 0) noexcept; [[nodiscard]] Error* compile_function(int decorators = 0) noexcept;
[[nodiscard]] Error* compile_class(int decorators = 0) noexcept; [[nodiscard]] Error* compile_class(int decorators = 0) noexcept;

View File

@ -47,13 +47,14 @@ inline void delete_expr(Expr* p) noexcept{
struct CodeEmitContext{ struct CodeEmitContext{
VM* vm; VM* vm;
FuncDecl_ func; // optional FuncDecl* func; // optional, weakref
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) {
func = NULL;
c11_smallmap_s2n__ctor(&_co_consts_string_dedup_map); c11_smallmap_s2n__ctor(&_co_consts_string_dedup_map);
} }
@ -73,7 +74,6 @@ struct CodeEmitContext{
int add_varname(StrName name) noexcept; int add_varname(StrName name) noexcept;
int add_const(PyVar) noexcept; int add_const(PyVar) noexcept;
int add_const_string(std::string_view) noexcept; int add_const_string(std::string_view) noexcept;
int add_func_decl(FuncDecl_ decl) noexcept;
void emit_store_name(NameScope scope, StrName name, int line) noexcept; void emit_store_name(NameScope scope, StrName name, int line) noexcept;
void try_merge_for_iter_store(int) noexcept; void try_merge_for_iter_store(int) noexcept;
// emit top -> pop -> delete // emit top -> pop -> delete
@ -366,12 +366,11 @@ struct CompExpr : Expr {
}; };
struct LambdaExpr : Expr { struct LambdaExpr : Expr {
FuncDecl_ decl; int index;
LambdaExpr(FuncDecl_ decl) : decl(decl) {} LambdaExpr(int index) : index(index) {}
void emit_(CodeEmitContext* ctx) override { void emit_(CodeEmitContext* ctx) override {
int index = ctx->add_func_decl(decl);
ctx->emit_(OP_LOAD_FUNCTION, index, line); ctx->emit_(OP_LOAD_FUNCTION, index, line);
} }
}; };

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "pocketpy/objects/codeobject.h"
#include "pocketpy/objects/codeobject.hpp" #include "pocketpy/objects/codeobject.hpp"
namespace pkpy { namespace pkpy {
@ -117,21 +118,21 @@ struct Frame {
PyVar* f_closure_try_get(StrName name); PyVar* f_closure_try_get(StrName name);
int ip() const { return _ip - co->codes.data(); } int ip() const { return _ip - (Bytecode*)co->codes.data; }
// function scope // function scope
Frame(PyVar* p0, const CodeObject* co, PyObject* _module, PyObject* _callable, PyVar* _locals_base) : Frame(PyVar* p0, const CodeObject* co, PyObject* _module, PyObject* _callable, PyVar* _locals_base) :
_ip(co->codes.data() - 1), _sp_base(p0), co(co), _module(_module), _callable(_callable), _ip((Bytecode*)co->codes.data - 1), _sp_base(p0), co(co), _module(_module), _callable(_callable),
_locals(co, _locals_base), _uw_list(nullptr) {} _locals(co, _locals_base), _uw_list(nullptr) {}
// exec/eval // exec/eval
Frame(PyVar* p0, const CodeObject* co, PyObject* _module, PyObject* _callable, FastLocals _locals) : Frame(PyVar* p0, const CodeObject* co, PyObject* _module, PyObject* _callable, FastLocals _locals) :
_ip(co->codes.data() - 1), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(_locals), _ip((Bytecode*)co->codes.data - 1), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(_locals),
_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), _module(_module), _callable(nullptr), _ip((Bytecode*)co->codes.data - 1), _sp_base(p0), co(co), _module(_module), _callable(nullptr),
_locals(co, 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,12 +144,15 @@ 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->blocks[co->lines[ip()].iblock].end; int iblock = c11__getitem(BytecodeEx, &co->codes_ex, ip()).iblock;
int target = c11__getitem(CodeBlock, &co->blocks, iblock).end;
prepare_jump_break(s_data, target); prepare_jump_break(s_data, target);
return target; return target;
} }
int curr_lineno() const { return co->lines[ip()].lineno; } int curr_lineno() const {
return c11__getitem(BytecodeEx, &co->codes_ex, ip()).lineno;
}
void set_unwind_target(PyVar* _sp); void set_unwind_target(PyVar* _sp);
UnwindTarget* find_unwind_target(int iblock); UnwindTarget* find_unwind_target(int iblock);

View File

@ -501,7 +501,7 @@ public:
void __pop_frame(); void __pop_frame();
PyVar __py_generator(LinkedFrame* frame, ArgsView buffer); PyVar __py_generator(LinkedFrame* frame, ArgsView buffer);
void __op_unpack_sequence(uint16_t arg); void __op_unpack_sequence(uint16_t arg);
void __prepare_py_call(PyVar*, ArgsView, ArgsView, const FuncDecl_&); void __prepare_py_call(PyVar*, ArgsView, ArgsView, const FuncDecl*);
void __unpack_as_list(ArgsView args, List& list); void __unpack_as_list(ArgsView args, List& list);
void __unpack_as_dict(ArgsView args, Dict& dict); void __unpack_as_dict(ArgsView args, Dict& dict);
[[noreturn]] void __raise_exc(bool re_raise = false); [[noreturn]] void __raise_exc(bool re_raise = false);

View File

@ -3,6 +3,12 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "pocketpy/common/vector.h"
#include "pocketpy/common/smallmap.h"
#include "pocketpy/objects/base.h"
#include "pocketpy/objects/sourcedata.h"
#include "pocketpy/common/refcount.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -52,7 +58,6 @@ typedef struct Bytecode {
void Bytecode__set_signed_arg(Bytecode* self, int arg); void Bytecode__set_signed_arg(Bytecode* self, int arg);
bool Bytecode__is_forward_jump(const Bytecode* self); bool Bytecode__is_forward_jump(const Bytecode* self);
typedef struct CodeBlock { typedef struct CodeBlock {
CodeBlockType type; CodeBlockType type;
int parent; // parent index in blocks int parent; // parent index in blocks
@ -61,6 +66,67 @@ typedef struct CodeBlock {
int end2; // ... int end2; // ...
} CodeBlock; } CodeBlock;
typedef struct BytecodeEx {
int lineno; // line number for each bytecode
bool is_virtual; // whether this bytecode is virtual (not in source code)
int iblock; // block index
} BytecodeEx;
typedef struct CodeObject {
pkpy_SourceData_ src;
pkpy_Str name;
c11_vector/*T=Bytecode*/ codes;
c11_vector/*T=CodeObjectByteCodeEx*/ codes_ex;
c11_vector/*T=PyVar*/ consts; // constants
c11_vector/*T=StrName*/ varnames; // local variables
int nlocals; // cached varnames.size()
c11_smallmap_n2i varnames_inv;
c11_smallmap_n2i labels;
c11_vector/*T=CodeBlock*/ blocks;
c11_vector/*T=FuncDecl_*/ func_decls;
int start_line;
int end_line;
} CodeObject;
CodeObject* CodeObject__new(pkpy_SourceData_ src, c11_string name);
void CodeObject__delete(CodeObject* self);
void CodeObject__gc_mark(const CodeObject* self);
typedef struct FuncDeclKwArg{
int index; // index in co->varnames
uint16_t key; // name of this argument
PyVar value; // default value
} FuncDeclKwArg;
typedef struct FuncDecl {
RefCounted rc;
CodeObject* code; // strong ref
c11_vector/*T=int*/ args; // indices in co->varnames
c11_vector/*T=KwArg*/ kwargs; // indices in co->varnames
int starred_arg; // index in co->varnames, -1 if no *arg
int starred_kwarg; // index in co->varnames, -1 if no **kwarg
bool nested; // whether this function is nested
const char* docstring; // docstring of this function (weak ref)
FuncType type;
c11_smallmap_n2i kw_to_index;
} FuncDecl;
typedef FuncDecl* FuncDecl_;
FuncDecl_ FuncDecl__rcnew(pkpy_SourceData_ src, c11_string name);
void FuncDecl__dtor(FuncDecl* self);
void FuncDecl__add_kwarg(FuncDecl* self, int index, uint16_t key, const PyVar* value);
void FuncDecl__gc_mark(const FuncDecl* self);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -12,96 +12,6 @@ namespace pkpy {
typedef PyVar (*NativeFuncC)(VM*, ArgsView); typedef PyVar (*NativeFuncC)(VM*, ArgsView);
struct CodeObject;
struct FuncDecl;
using FuncDecl_ = std::shared_ptr<FuncDecl>;
struct CodeObject {
PK_ALWAYS_PASS_BY_POINTER(CodeObject)
struct LineInfo {
int lineno; // line number for each bytecode
bool is_virtual; // whether this bytecode is virtual (not in source code)
int iblock; // block index
};
pkpy_SourceData_ src;
Str name;
vector<Bytecode> codes;
vector<LineInfo> lines;
small_vector_2<PyVar, 8> consts; // constants
small_vector_2<StrName, 8> varnames; // local variables
int nlocals; // varnames.size()
c11_smallmap_n2i varnames_inv;
vector<CodeBlock> blocks;
c11_smallmap_n2i labels;
vector<FuncDecl_> func_decls;
int start_line;
int end_line;
void _gc_mark(VM*) const;
CodeObject(pkpy_SourceData_ src, const Str& name) :
src(src), name(name), nlocals(0), start_line(-1), end_line(-1) {
blocks.push_back(CodeBlock{CodeBlockType_NO_BLOCK, -1, 0, -1, -1});
c11_smallmap_n2i__ctor(&varnames_inv);
c11_smallmap_n2i__ctor(&labels);
PK_INCREF(src);
}
~CodeObject() {
c11_smallmap_n2i__dtor(&varnames_inv);
c11_smallmap_n2i__dtor(&labels);
PK_DECREF(src);
}
};
struct FuncDecl {
PK_ALWAYS_PASS_BY_POINTER(FuncDecl)
struct KwArg {
int index; // index in co->varnames
StrName key; // name of this argument
PyVar value; // default value
};
CodeObject* code; // strong ref
small_vector_2<int, 8> args; // 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_kwarg = -1; // index in co->varnames, -1 if no **kwarg
bool nested = false; // whether this function is nested
const char* docstring; // docstring of this function (weak ref)
FuncType type = FuncType_UNSET;
c11_smallmap_n2i kw_to_index;
void add_kwarg(int index, StrName key, PyVar value) {
c11_smallmap_n2i__set(&kw_to_index, key.index, index);
c11_vector__push(KwArg, &kwargs, (KwArg{index, key.index, value}));
}
void _gc_mark(VM*) const;
FuncDecl(CodeObject* code){
this->code = code;
c11_vector__ctor(&kwargs, sizeof(KwArg));
c11_smallmap_n2i__ctor(&kw_to_index);
}
~FuncDecl(){
delete code;
c11_vector__dtor(&kwargs);
c11_smallmap_n2i__dtor(&kw_to_index);
}
};
struct NativeFunc { struct NativeFunc {
NativeFuncC f; NativeFuncC f;
int argc; // old style argc-based call int argc; // old style argc-based call
@ -117,6 +27,10 @@ struct NativeFunc {
PyVar call(VM* vm, ArgsView args) const { return f(vm, args); } PyVar call(VM* vm, ArgsView args) const { return f(vm, args); }
void _gc_mark(VM*) const; void _gc_mark(VM*) const;
~NativeFunc() {
if(decl) PK_DECREF(decl);
}
}; };
struct Function { struct Function {
@ -128,11 +42,14 @@ struct Function {
NameDict* _closure; // strong ref NameDict* _closure; // strong ref
Function(FuncDecl_ decl, PyObject* _module, PyObject* _class, NameDict* _closure) : Function(FuncDecl_ decl, PyObject* _module, PyObject* _class, NameDict* _closure) :
decl(decl), _module(_module), _class(_class), _closure(_closure) {} decl(decl), _module(_module), _class(_class), _closure(_closure) {
PK_INCREF(decl);
}
void _gc_mark(VM*) const; void _gc_mark(VM*) const;
~Function() { ~Function() {
PK_DECREF(decl);
delete _closure; delete _closure;
} }
}; };

View File

@ -25,14 +25,14 @@ void pkpy_SourceData__ctor(struct pkpy_SourceData* self,
// Skip utf8 BOM if there is any. // Skip utf8 BOM if there is any.
if (source.size >= 3 && strncmp(source.data, "\xEF\xBB\xBF", 3) == 0) index += 3; if (source.size >= 3 && strncmp(source.data, "\xEF\xBB\xBF", 3) == 0) index += 3;
// Drop all '\r' // Drop all '\r'
pkpy_SStream ss; pk_SStream ss;
pkpy_SStream__ctor2(&ss, source.size + 1); pk_SStream__ctor2(&ss, source.size + 1);
while(index < source.size){ while(index < source.size){
char c = source.data[index]; char c = source.data[index];
if(c != '\r') pkpy_SStream__write_char(&ss, c); if(c != '\r') pk_SStream__write_char(&ss, c);
index++; index++;
} }
self->source = pkpy_SStream__submit(&ss); self->source = pk_SStream__submit(&ss);
self->is_precompiled = (strncmp(pkpy_Str__data(&self->source), "pkpy:", 5) == 0); self->is_precompiled = (strncmp(pkpy_Str__data(&self->source), "pkpy:", 5) == 0);
c11_vector__push(const char*, &self->line_starts, pkpy_Str__data(&self->source)); c11_vector__push(const char*, &self->line_starts, pkpy_Str__data(&self->source));
} }
@ -63,46 +63,46 @@ bool pkpy_SourceData__get_line(const struct pkpy_SourceData* self, int lineno, c
} }
pkpy_Str pkpy_SourceData__snapshot(const struct pkpy_SourceData* self, int lineno, const char* cursor, const char* name) { pkpy_Str pkpy_SourceData__snapshot(const struct pkpy_SourceData* self, int lineno, const char* cursor, const char* name) {
pkpy_SStream ss; pk_SStream ss;
pkpy_SStream__ctor(&ss); pk_SStream__ctor(&ss);
// pkpy_SStream__write_cstr(&ss, " File \""); // pk_SStream__write_cstr(&ss, " File \"");
// pkpy_SStream__write_Str(&ss, &self->filename); // pk_SStream__write_Str(&ss, &self->filename);
// pkpy_SStream__write_cstr(&ss, "\", line "); // pk_SStream__write_cstr(&ss, "\", line ");
// pkpy_SStream__write_int(&ss, lineno); // pk_SStream__write_int(&ss, lineno);
pkpy_SStream__write(&ss, pk_SStream__write(&ss,
" File \"{}\", line {}", " File \"{}\", line {}",
&self->filename, &self->filename,
lineno lineno
); );
if(name && *name) { if(name && *name) {
pkpy_SStream__write_cstr(&ss, ", in "); pk_SStream__write_cstr(&ss, ", in ");
pkpy_SStream__write_cstr(&ss, name); pk_SStream__write_cstr(&ss, name);
} }
if(!self->is_precompiled) { if(!self->is_precompiled) {
pkpy_SStream__write_char(&ss, '\n'); pk_SStream__write_char(&ss, '\n');
const char *st = NULL, *ed; const char *st = NULL, *ed;
if(pkpy_SourceData__get_line(self, lineno, &st, &ed)) { if(pkpy_SourceData__get_line(self, lineno, &st, &ed)) {
while(st < ed && isblank(*st)) while(st < ed && isblank(*st))
++st; ++st;
if(st < ed) { if(st < ed) {
pkpy_SStream__write_cstr(&ss, " "); pk_SStream__write_cstr(&ss, " ");
pkpy_SStream__write_cstrn(&ss, st, ed - st); pk_SStream__write_cstrn(&ss, st, ed - st);
if(cursor && st <= cursor && cursor <= ed) { if(cursor && st <= cursor && cursor <= ed) {
pkpy_SStream__write_cstr(&ss, "\n "); pk_SStream__write_cstr(&ss, "\n ");
for(int i = 0; i < (cursor - st); ++i) for(int i = 0; i < (cursor - st); ++i)
pkpy_SStream__write_char(&ss, ' '); pk_SStream__write_char(&ss, ' ');
pkpy_SStream__write_cstr(&ss, "^"); pk_SStream__write_cstr(&ss, "^");
} }
} else { } else {
st = NULL; st = NULL;
} }
} }
if(!st) { pkpy_SStream__write_cstr(&ss, " <?>"); } if(!st) { pk_SStream__write_cstr(&ss, " <?>"); }
} }
return pkpy_SStream__submit(&ss); return pk_SStream__submit(&ss);
} }

View File

@ -1,4 +1,5 @@
#include "pocketpy/common/sstream.h" #include "pocketpy/common/sstream.h"
#include "pocketpy/common/config.h"
#include "pocketpy/common/utils.h" #include "pocketpy/common/utils.h"
#include <stdio.h> #include <stdio.h>
@ -6,39 +7,39 @@
#include <ctype.h> #include <ctype.h>
#include <math.h> #include <math.h>
void pkpy_SStream__ctor(pkpy_SStream* self) { void pk_SStream__ctor(pk_SStream* self) {
c11_vector__ctor(&self->data, sizeof(char)); c11_vector__ctor(&self->data, sizeof(char));
} }
void pkpy_SStream__ctor2(pkpy_SStream* self, int capacity) { void pk_SStream__ctor2(pk_SStream* self, int capacity) {
c11_vector__ctor(&self->data, sizeof(char)); c11_vector__ctor(&self->data, sizeof(char));
c11_vector__reserve(&self->data, capacity); c11_vector__reserve(&self->data, capacity);
} }
void pkpy_SStream__dtor(pkpy_SStream* self) { void pk_SStream__dtor(pk_SStream* self) {
c11_vector__dtor(&self->data); c11_vector__dtor(&self->data);
} }
void pkpy_SStream__write_char(pkpy_SStream* self, char c) { void pk_SStream__write_char(pk_SStream* self, char c) {
c11_vector__push(char, &self->data, c); c11_vector__push(char, &self->data, c);
} }
void pkpy_SStream__write_int(pkpy_SStream* self, int i) { void pk_SStream__write_int(pk_SStream* self, int i) {
char buf[12]; // sign + 10 digits + null terminator char buf[12]; // sign + 10 digits + null terminator
snprintf(buf, sizeof(buf), "%d", i); snprintf(buf, sizeof(buf), "%d", i);
pkpy_SStream__write_cstr(self, buf); pk_SStream__write_cstr(self, buf);
} }
void pkpy_SStream__write_i64(pkpy_SStream* self, int64_t val) { void pk_SStream__write_i64(pk_SStream* self, int64_t val) {
// sign + 21 digits + null terminator // sign + 21 digits + null terminator
// str(-2**64).__len__() == 21 // str(-2**64).__len__() == 21
c11_vector__reserve(&self->data, self->data.count + 23); c11_vector__reserve(&self->data, self->data.count + 23);
if(val == 0){ if(val == 0){
pkpy_SStream__write_char(self, '0'); pk_SStream__write_char(self, '0');
return; return;
} }
if(val < 0){ if(val < 0){
pkpy_SStream__write_char(self, '-'); pk_SStream__write_char(self, '-');
val = -val; val = -val;
} }
int start = self->data.count; int start = self->data.count;
@ -50,17 +51,17 @@ void pkpy_SStream__write_i64(pkpy_SStream* self, int64_t val) {
c11_vector__reverse(char, &self->data, start, end); c11_vector__reverse(char, &self->data, start, end);
} }
void pkpy_SStream__write_float(pkpy_SStream* self, float val, int precision){ void pk_SStream__write_float(pk_SStream* self, float val, int precision){
pkpy_SStream__write_double(self, val, precision); pk_SStream__write_double(self, val, precision);
} }
void pkpy_SStream__write_double(pkpy_SStream* self, double val, int precision){ void pk_SStream__write_double(pk_SStream* self, double val, int precision){
if(isinf(val)) { if(isinf(val)) {
pkpy_SStream__write_cstr(self, val > 0 ? "inf" : "-inf"); pk_SStream__write_cstr(self, val > 0 ? "inf" : "-inf");
return; return;
} }
if(isnan(val)) { if(isnan(val)) {
pkpy_SStream__write_cstr(self, "nan"); pk_SStream__write_cstr(self, "nan");
return; return;
} }
char b[32]; char b[32];
@ -72,90 +73,102 @@ void pkpy_SStream__write_double(pkpy_SStream* self, double val, int precision){
int prec = precision; int prec = precision;
size = snprintf(b, sizeof(b), "%.*f", prec, val); size = snprintf(b, sizeof(b), "%.*f", prec, val);
} }
pkpy_SStream__write_cstr(self, b); pk_SStream__write_cstr(self, b);
bool all_is_digit = true; bool all_is_digit = true;
for(int i = 1; i < size; i++){ for(int i = 1; i < size; i++){
if(!isdigit(b[i])){ all_is_digit = false; break; } if(!isdigit(b[i])){ all_is_digit = false; break; }
} }
if(all_is_digit) pkpy_SStream__write_cstr(self, ".0"); if(all_is_digit) pk_SStream__write_cstr(self, ".0");
} }
void pkpy_SStream__write_Str(pkpy_SStream* self, const pkpy_Str* str) { void pk_SStream__write_Str(pk_SStream* self, const pkpy_Str* str) {
pkpy_SStream__write_cstrn(self, pkpy_Str__data(str), str->size); pk_SStream__write_cstrn(self, pkpy_Str__data(str), str->size);
} }
void pkpy_SStream__write_sv(pkpy_SStream* self, c11_string sv) { void pk_SStream__write_sv(pk_SStream* self, c11_string sv) {
pkpy_SStream__write_cstrn(self, sv.data, sv.size); pk_SStream__write_cstrn(self, sv.data, sv.size);
} }
void pkpy_SStream__write_cstr(pkpy_SStream* self, const char* str) { void pk_SStream__write_cstr(pk_SStream* self, const char* str) {
pkpy_SStream__write_cstrn(self, str, strlen(str)); pk_SStream__write_cstrn(self, str, strlen(str));
} }
void pkpy_SStream__write_cstrn(pkpy_SStream* self, const char* str, int n) { void pk_SStream__write_cstrn(pk_SStream* self, const char* str, int n) {
c11_vector__extend(char, &self->data, str, n); c11_vector__extend(char, &self->data, str, n);
} }
void pkpy_SStream__write_hex(pkpy_SStream* self, unsigned char c, bool non_zero) { void pk_SStream__write_hex(pk_SStream* self, unsigned char c, bool non_zero) {
unsigned char high = c >> 4; unsigned char high = c >> 4;
unsigned char low = c & 0xf; unsigned char low = c & 0xf;
if(non_zero) { if(non_zero) {
if(high) pkpy_SStream__write_char(self, PK_HEX_TABLE[high]); if(high) pk_SStream__write_char(self, PK_HEX_TABLE[high]);
if(high || low) pkpy_SStream__write_char(self, PK_HEX_TABLE[low]); if(high || low) pk_SStream__write_char(self, PK_HEX_TABLE[low]);
} else { } else {
pkpy_SStream__write_char(self, PK_HEX_TABLE[high]); pk_SStream__write_char(self, PK_HEX_TABLE[high]);
pkpy_SStream__write_char(self, PK_HEX_TABLE[low]); pk_SStream__write_char(self, PK_HEX_TABLE[low]);
} }
} }
void pkpy_SStream__write_ptr(pkpy_SStream* self, void* p) { void pk_SStream__write_ptr(pk_SStream* self, void* p) {
if(p == NULL) { if(p == NULL) {
pkpy_SStream__write_cstr(self, "0x0"); pk_SStream__write_cstr(self, "0x0");
return; return;
} }
pkpy_SStream__write_cstr(self, "0x"); pk_SStream__write_cstr(self, "0x");
uintptr_t p_t = (uintptr_t)(p); uintptr_t p_t = (uintptr_t)(p);
bool non_zero = true; bool non_zero = true;
for(int i = sizeof(void*) - 1; i >= 0; i--) { for(int i = sizeof(void*) - 1; i >= 0; i--) {
unsigned char cpnt = (p_t >> (i * 8)) & 0xff; unsigned char cpnt = (p_t >> (i * 8)) & 0xff;
pkpy_SStream__write_hex(self, cpnt, non_zero); pk_SStream__write_hex(self, cpnt, non_zero);
if(cpnt != 0) non_zero = false; if(cpnt != 0) non_zero = false;
} }
} }
void pkpy_SStream__write_any(pkpy_SStream* self, const char* fmt, const pkpy_AnyStr* args, int n){ void pk_SStream__write_any(pk_SStream* self, const char* fmt, const pk_AnyStr* args, int n){
int i = 0; int i = 0;
while(*fmt){ while(*fmt){
if(*fmt == '{' && fmt[1] == '}'){ if(*fmt == '{' && fmt[1] == '}'){
assert(i < n); assert(i < n);
switch(args[i].type){ switch(args[i].type){
case 1: pkpy_SStream__write_int(self, args[i]._int); break; case 1: pk_SStream__write_int(self, args[i]._int); break;
case 2: pkpy_SStream__write_i64(self, args[i]._i64); break; case 2: pk_SStream__write_i64(self, args[i]._i64); break;
case 3: pkpy_SStream__write_float(self, args[i]._float, -1); break; case 3: pk_SStream__write_float(self, args[i]._float, -1); break;
case 4: pkpy_SStream__write_double(self, args[i]._double, -1); break; case 4: pk_SStream__write_double(self, args[i]._double, -1); break;
case 5: pkpy_SStream__write_char(self, args[i]._char); break; case 5: pk_SStream__write_char(self, args[i]._char); break;
case 6: pkpy_SStream__write_Str(self, args[i]._str); break; case 6: pk_SStream__write_Str(self, args[i]._str); break;
case 7: pkpy_SStream__write_sv(self, args[i]._sv); break; case 7: pk_SStream__write_sv(self, args[i]._sv); break;
case 8: pkpy_SStream__write_cstr(self, args[i]._cstr); break; case 8: pk_SStream__write_cstr(self, args[i]._cstr); break;
case 9: assert(0); break; case 9: pk_SStream__write_ptr(self, args[i]._ptr); break;
default: assert(0); break; default: assert(0); break;
} }
fmt += 2; fmt += 2;
i++; i++;
}else{ }else{
pkpy_SStream__write_char(self, *fmt); pk_SStream__write_char(self, *fmt);
fmt++; fmt++;
} }
} }
} }
pkpy_Str pkpy_SStream__submit(pkpy_SStream* self) { pkpy_Str pk_SStream__submit(pk_SStream* self) {
c11_vector__push(char, &self->data, '\0'); c11_vector__push(char, &self->data, '\0');
pkpy_Str retval = { pkpy_Str retval = {
.size = self->data.count - 1, .size = self->data.count - 1,
.is_ascii = false, // need to check .is_ascii = c11__isascii((char*)self->data.data, self->data.count),
.is_sso = false, .is_sso = false,
._ptr = (char*)self->data.data ._ptr = (char*)self->data.data
}; };
return retval; return retval;
} }
const char* pk_format_any(const char* fmt, const pk_AnyStr* args, int n){
PK_THREAD_LOCAL pk_SStream ss;
if(ss.data.elem_size == 0){
pk_SStream__ctor2(&ss, 128);
}else{
c11_vector__clear(&ss.data);
}
pk_SStream__write_any(&ss, fmt, args, n);
pk_SStream__write_char(&ss, '\0');
return (const char*)ss.data.data;
}

View File

@ -1,5 +1,6 @@
#include "pocketpy/compiler/compiler.hpp" #include "pocketpy/compiler/compiler.hpp"
#include "pocketpy/common/config.h" #include "pocketpy/common/config.h"
#include "pocketpy/compiler/expr.hpp"
#include "pocketpy/interpreter/vm.hpp" #include "pocketpy/interpreter/vm.hpp"
#include "pocketpy/objects/codeobject.hpp" #include "pocketpy/objects/codeobject.hpp"
@ -21,17 +22,21 @@ NameScope Compiler::name_scope() const noexcept{
} }
CodeObject* Compiler::push_global_context() noexcept{ CodeObject* Compiler::push_global_context() noexcept{
CodeObject* co = new CodeObject(lexer.src, static_cast<const Str&>(lexer.src->filename)); CodeObject* co = CodeObject__new(lexer.src, pkpy_Str__sv(&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(c11_string name, int* out_index) noexcept{
CodeObject* co = new CodeObject(lexer.src, name); FuncDecl_ decl = FuncDecl__rcnew(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;
// add_func_decl
CodeEmitContext* ctx = &contexts.back();
c11_vector__push(FuncDecl_, &ctx->co->func_decls, decl);
*out_index = ctx->co->func_decls.count - 1;
// push new context
contexts.push_back(CodeEmitContext(vm, decl->code, contexts.size())); contexts.push_back(CodeEmitContext(vm, decl->code, contexts.size()));
contexts.back().func = decl; contexts.back().func = decl;
return decl; return decl;
@ -54,29 +59,29 @@ Error* Compiler::pop_context() noexcept{
if(ctx()->co->nlocals > PK_MAX_CO_VARNAMES) { if(ctx()->co->nlocals > PK_MAX_CO_VARNAMES) {
return SyntaxError("maximum number of local variables exceeded"); return SyntaxError("maximum number of local variables exceeded");
} }
if(ctx()->co->consts.size() > 65530) { if(ctx()->co->consts.count > 65530) {
return SyntaxError("maximum number of constants exceeded"); return SyntaxError("maximum number of constants exceeded");
} }
// pre-compute LOOP_BREAK and LOOP_CONTINUE // pre-compute LOOP_BREAK and LOOP_CONTINUE
for(int i = 0; i < codes.size(); i++) { for(int i = 0; i < codes.count; i++) {
Bytecode& bc = codes[i]; Bytecode bc = c11__getitem(Bytecode, &codes, i);
if(bc.op == OP_LOOP_CONTINUE) { if(bc.op == OP_LOOP_CONTINUE) {
CodeBlock* block = &ctx()->co->blocks[bc.arg]; CodeBlock* block = c11__at(CodeBlock, &ctx()->co->blocks, bc.arg);
Bytecode__set_signed_arg(&bc, block->start - i); Bytecode__set_signed_arg(&bc, block->start - i);
} else if(bc.op == OP_LOOP_BREAK) { } else if(bc.op == OP_LOOP_BREAK) {
CodeBlock* block = &ctx()->co->blocks[bc.arg]; CodeBlock* block = c11__at(CodeBlock, &ctx()->co->blocks, bc.arg);
Bytecode__set_signed_arg(&bc, (block->end2 != -1 ? block->end2 : block->end) - i); Bytecode__set_signed_arg(&bc, (block->end2 != -1 ? block->end2 : block->end) - i);
} }
} }
// pre-compute func->is_simple // pre-compute func->is_simple
FuncDecl_ func = contexts.back().func; FuncDecl* func = contexts.back().func;
if(func) { if(func) {
// check generator // check generator
for(Bytecode bc: func->code->codes) { c11_vector__foreach(Bytecode, &func->code->codes, bc) {
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) { c11_vector__foreach(Bytecode, &func->code->codes, bc) {
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");
} }
} }
@ -93,9 +98,11 @@ Error* Compiler::pop_context() noexcept{
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.count == 1) {
Bytecode bc = func->code->codes[0]; Bytecode bc = c11__getitem(Bytecode, &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
@ -261,7 +268,8 @@ Error* Compiler::exprFString() noexcept{
Error* Compiler::exprLambda() noexcept{ Error* Compiler::exprLambda() noexcept{
Error* err; Error* err;
FuncDecl_ decl = push_f_context("<lambda>"); int decl_index;
FuncDecl_ decl = push_f_context({"<lambda>", 8}, &decl_index);
int line = prev().line; // backup line int line = prev().line; // backup line
if(!match(TK_COLON)) { if(!match(TK_COLON)) {
check(_compile_f_args(decl, false)); check(_compile_f_args(decl, false));
@ -272,7 +280,7 @@ Error* Compiler::exprLambda() noexcept{
ctx()->s_emit_top(); ctx()->s_emit_top();
ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE); ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
check(pop_context()); check(pop_context());
LambdaExpr* e = make_expr<LambdaExpr>(decl); LambdaExpr* e = make_expr<LambdaExpr>(decl_index);
e->line = line; e->line = line;
ctx()->s_push(e); ctx()->s_push(e);
return NULL; return NULL;
@ -744,7 +752,7 @@ Error* Compiler::compile_while_loop() noexcept{
// optional else clause // optional else clause
if(match(TK_ELSE)) { if(match(TK_ELSE)) {
check(compile_block_body()); check(compile_block_body());
block->end2 = ctx()->co->codes.size(); block->end2 = ctx()->co->codes.count;
} }
return NULL; return NULL;
} }
@ -769,7 +777,7 @@ Error* Compiler::compile_for_loop() noexcept{
// optional else clause // optional else clause
if(match(TK_ELSE)) { if(match(TK_ELSE)) {
check(compile_block_body()); check(compile_block_body());
block->end2 = ctx()->co->codes.size(); block->end2 = ctx()->co->codes.count;
} }
return NULL; return NULL;
} }
@ -815,17 +823,18 @@ Error* Compiler::compile_try_except() noexcept{
if(match(TK_FINALLY)) { if(match(TK_FINALLY)) {
int patch = ctx()->emit_(OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE); int patch = ctx()->emit_(OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE);
finally_entry = ctx()->co->codes.size(); finally_entry = ctx()->co->codes.count;
check(compile_block_body()); check(compile_block_body());
ctx()->emit_(OP_JUMP_ABSOLUTE_TOP, BC_NOARG, BC_KEEPLINE); ctx()->emit_(OP_JUMP_ABSOLUTE_TOP, BC_NOARG, BC_KEEPLINE);
ctx()->patch_jump(patch); ctx()->patch_jump(patch);
} }
// no match, re-raise // no match, re-raise
if(finally_entry != -1) { if(finally_entry != -1) {
i64 target = ctx()->co->codes.size() + 2; i64 target = ctx()->co->codes.count + 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);
Bytecode__set_signed_arg(&ctx()->co->codes[i], finally_entry - i); Bytecode* bc = c11__at(Bytecode, &ctx()->co->codes, i);
Bytecode__set_signed_arg(bc, finally_entry - i);
} }
ctx()->emit_(OP_RE_RAISE, BC_NOARG, BC_KEEPLINE); ctx()->emit_(OP_RE_RAISE, BC_NOARG, BC_KEEPLINE);
@ -833,10 +842,11 @@ Error* Compiler::compile_try_except() noexcept{
for(int patch: patches) for(int patch: patches)
ctx()->patch_jump(patch); ctx()->patch_jump(patch);
if(finally_entry != -1) { if(finally_entry != -1) {
i64 target = ctx()->co->codes.size() + 2; i64 target = ctx()->co->codes.count + 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);
Bytecode__set_signed_arg(&ctx()->co->codes[i], finally_entry - i); Bytecode* bc = c11__at(Bytecode, &ctx()->co->codes, i);
Bytecode__set_signed_arg(bc, finally_entry - i);
} }
return NULL; return NULL;
} }
@ -1144,7 +1154,7 @@ Error* Compiler::compile_class(int decorators) noexcept{
return NULL; return NULL;
} }
Error* Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints) noexcept{ Error* Compiler::_compile_f_args(FuncDecl* decl, bool enable_type_hints) noexcept{
int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
Error* err; Error* err;
do { do {
@ -1163,17 +1173,23 @@ Error* Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints) noexcep
StrName name(prev().sv()); StrName name(prev().sv());
// check duplicate argument name // check duplicate argument name
for(int j: decl->args) { uint16_t tmp_name;
if(decl->code->varnames[j] == name) return SyntaxError("duplicate argument name"); c11_vector__foreach(int, &decl->args, j) {
tmp_name = c11__getitem(uint16_t, &decl->args, *j);
if(tmp_name == name.index) return SyntaxError("duplicate argument name");
} }
c11_vector__foreach(FuncDecl::KwArg, &decl->kwargs, kv) { c11_vector__foreach(FuncDeclKwArg, &decl->kwargs, kv) {
if(decl->code->varnames[kv->index] == name) return SyntaxError("duplicate argument name"); tmp_name = c11__getitem(uint16_t, &decl->code->varnames, kv->index);
if(tmp_name == name.index) return SyntaxError("duplicate argument name");
} }
if(decl->starred_arg != -1 && decl->code->varnames[decl->starred_arg] == name) {
return SyntaxError("duplicate argument name"); if(decl->starred_arg != -1) {
tmp_name = c11__getitem(uint16_t, &decl->code->varnames, decl->starred_arg);
if(tmp_name == name.index) return SyntaxError("duplicate argument name");
} }
if(decl->starred_kwarg != -1 && decl->code->varnames[decl->starred_kwarg] == name) { if(decl->starred_kwarg != -1) {
return SyntaxError("duplicate argument name"); tmp_name = c11__getitem(uint16_t, &decl->code->varnames, decl->starred_kwarg);
if(tmp_name == name.index) return SyntaxError("duplicate argument name");
} }
// eat type hints // eat type hints
@ -1181,7 +1197,9 @@ Error* Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints) noexcep
if(state == 0 && curr().type == TK_ASSIGN) state = 2; if(state == 0 && curr().type == TK_ASSIGN) state = 2;
int index = ctx()->add_varname(name); int index = ctx()->add_varname(name);
switch(state) { switch(state) {
case 0: decl->args.push_back(index); break; case 0:
c11_vector__push(int, &decl->args, index);
break;
case 1: case 1:
decl->starred_arg = index; decl->starred_arg = index;
state += 1; state += 1;
@ -1191,7 +1209,7 @@ Error* Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints) noexcep
PyVar value; PyVar value;
check(read_literal(&value)); check(read_literal(&value));
if(value == nullptr) return SyntaxError("default argument must be a literal"); if(value == nullptr) return SyntaxError("default argument must be a literal");
decl->add_kwarg(index, name, value); FuncDecl__add_kwarg(decl, index, name.index, (const ::PyVar*)&value);
} break; } break;
case 3: case 3:
decl->starred_kwarg = index; decl->starred_kwarg = index;
@ -1205,8 +1223,9 @@ Error* Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints) noexcep
Error* Compiler::compile_function(int decorators) noexcept{ Error* Compiler::compile_function(int decorators) noexcept{
Error* err; Error* err;
consume(TK_ID); consume(TK_ID);
Str decl_name = prev().str(); std::string_view decl_name = prev().sv();
FuncDecl_ decl = push_f_context(decl_name); int decl_index;
FuncDecl_ decl = push_f_context({decl_name.data(), (int)decl_name.size()}, &decl_index);
consume(TK_LPAREN); consume(TK_LPAREN);
if(!match(TK_RPAREN)) { if(!match(TK_RPAREN)) {
check(_compile_f_args(decl, true)); check(_compile_f_args(decl, true));
@ -1216,22 +1235,24 @@ Error* Compiler::compile_function(int decorators) noexcept{
check(compile_block_body()); check(compile_block_body());
check(pop_context()); check(pop_context());
decl->docstring = nullptr; if(decl->code->codes.count >= 2) {
if(decl->code->codes.size() >= 2 && decl->code->codes[0].op == OP_LOAD_CONST && Bytecode* codes = (Bytecode*)decl->code->codes.data;
decl->code->codes[1].op == OP_POP_TOP) { if(codes[0].op == OP_LOAD_CONST && codes[1].op == OP_POP_TOP) {
PyVar c = decl->code->consts[decl->code->codes[0].arg]; // handle optional docstring
if(is_type(c, vm->tp_str)) { PyVar* c = c11__at(PyVar, &decl->code->consts, codes[0].arg);
decl->code->codes[0].op = OP_NO_OP; if(is_type(*c, vm->tp_str)) {
decl->code->codes[1].op = OP_NO_OP; codes[0].op = OP_NO_OP;
decl->docstring = PK_OBJ_GET(Str, c).c_str(); codes[1].op = OP_NO_OP;
decl->docstring = PK_OBJ_GET(Str, *c).c_str();
}
} }
} }
ctx()->emit_(OP_LOAD_FUNCTION, ctx()->add_func_decl(decl), prev().line); ctx()->emit_(OP_LOAD_FUNCTION, decl_index, prev().line);
ctx()->s_emit_decorators(decorators); ctx()->s_emit_decorators(decorators);
if(!ctx()->is_compiling_class) { if(!ctx()->is_compiling_class) {
NameExpr* e = make_expr<NameExpr>(decl_name, name_scope()); NameExpr* e = make_expr<NameExpr>(StrName(decl_name), name_scope());
e->emit_store(ctx()); e->emit_store(ctx());
delete_expr(e); delete_expr(e);
} else { } else {

View File

@ -1,5 +1,7 @@
#include "pocketpy/compiler/expr.hpp" #include "pocketpy/compiler/expr.hpp"
#include "pocketpy/interpreter/vm.hpp" #include "pocketpy/interpreter/vm.hpp"
#include "pocketpy/objects/codeobject.h"
#include "pocketpy/objects/public.h"
namespace pkpy { namespace pkpy {
@ -16,23 +18,26 @@ 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; CodeBlock* block = c11__at(CodeBlock, &co->blocks, index);
if(co->blocks[index].type == CodeBlockType_WHILE_LOOP) break; if(block->type == CodeBlockType_FOR_LOOP) break;
index = co->blocks[index].parent; if(block->type == CodeBlockType_WHILE_LOOP) break;
index = block->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(), -1, -1}); CodeBlock block = {type, curr_iblock, co->codes.count, -1, -1};
curr_iblock = co->blocks.size() - 1; c11_vector__push(CodeBlock, &co->blocks, block);
return &co->blocks[curr_iblock]; curr_iblock = co->blocks.count - 1;
return c11__at(CodeBlock, &co->blocks, curr_iblock);
} }
void CodeEmitContext::exit_block() noexcept{ void CodeEmitContext::exit_block() noexcept{
auto curr_type = co->blocks[curr_iblock].type; CodeBlock* block = c11__at(CodeBlock, &co->blocks, curr_iblock);
co->blocks[curr_iblock].end = co->codes.size(); CodeBlockType curr_type = block->type;
curr_iblock = co->blocks[curr_iblock].parent; block->end = co->codes.count;
curr_iblock = block->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
@ -55,38 +60,37 @@ void CodeEmitContext::s_emit_decorators(int count) noexcept{
} }
int CodeEmitContext::emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual) noexcept{ int CodeEmitContext::emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual) noexcept{
co->codes.push_back(Bytecode{(uint8_t)opcode, arg}); c11_vector__push(Bytecode, &co->codes, (Bytecode{(uint8_t)opcode, arg}));
co->lines.push_back(CodeObject::LineInfo{line, is_virtual, curr_iblock}); c11_vector__push(BytecodeEx, &co->codes_ex, (BytecodeEx{line, is_virtual, curr_iblock}));
int i = co->codes.size() - 1; int i = co->codes.count - 1;
BytecodeEx* codes_ex = (BytecodeEx*)co->codes_ex.data;
if(line == BC_KEEPLINE) { if(line == BC_KEEPLINE) {
if(i >= 1) codes_ex[i].lineno = i>=1 ? codes_ex[i-1].lineno : 1;
co->lines[i].lineno = co->lines[i - 1].lineno;
else
co->lines[i].lineno = 1;
} }
return i; return i;
} }
void CodeEmitContext::revert_last_emit_() noexcept{ void CodeEmitContext::revert_last_emit_() noexcept{
co->codes.pop_back(); c11_vector__pop(Bytecode, &co->codes);
co->lines.pop_back(); c11_vector__pop(BytecodeEx, &co->codes_ex);
} }
void CodeEmitContext::try_merge_for_iter_store(int i) noexcept{ void CodeEmitContext::try_merge_for_iter_store(int i) noexcept{
// [FOR_ITER, STORE_?, ] // [FOR_ITER, STORE_?, ]
if(co->codes[i].op != OP_FOR_ITER) return; Bytecode* co_codes = (Bytecode*)co->codes.data;
if(co->codes.size() - i != 2) return; if(co_codes[i].op != OP_FOR_ITER) return;
uint16_t arg = co->codes[i + 1].arg; if(co->codes.count - i != 2) return;
if(co->codes[i + 1].op == OP_STORE_FAST) { uint16_t arg = co_codes[i + 1].arg;
if(co_codes[i + 1].op == OP_STORE_FAST) {
revert_last_emit_(); revert_last_emit_();
co->codes[i].op = OP_FOR_ITER_STORE_FAST; co_codes[i].op = OP_FOR_ITER_STORE_FAST;
co->codes[i].arg = arg; co_codes[i].arg = arg;
return; return;
} }
if(co->codes[i + 1].op == OP_STORE_GLOBAL) { if(co_codes[i + 1].op == OP_STORE_GLOBAL) {
revert_last_emit_(); revert_last_emit_();
co->codes[i].op = OP_FOR_ITER_STORE_GLOBAL; co_codes[i].op = OP_FOR_ITER_STORE_GLOBAL;
co->codes[i].arg = arg; co_codes[i].arg = arg;
return; return;
} }
} }
@ -100,14 +104,15 @@ 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(); Bytecode* co_codes = (Bytecode*)co->codes.data;
Bytecode__set_signed_arg(&co->codes[index], target - index); int target = co->codes.count;
Bytecode__set_signed_arg(&co_codes[index], target - index);
} }
bool CodeEmitContext::add_label(StrName name) noexcept{ bool CodeEmitContext::add_label(StrName name) noexcept{
bool ok = c11_smallmap_n2i__contains(&co->labels, name.index); bool ok = c11_smallmap_n2i__contains(&co->labels, name.index);
if(ok) return false; if(ok) return false;
c11_smallmap_n2i__set(&co->labels, name.index, co->codes.size()); c11_smallmap_n2i__set(&co->labels, name.index, co->codes.count);
return true; return true;
} }
@ -115,9 +120,9 @@ int CodeEmitContext::add_varname(StrName name) noexcept{
// PK_MAX_CO_VARNAMES will be checked when pop_context(), not here // PK_MAX_CO_VARNAMES will be checked when pop_context(), not here
int index = c11_smallmap_n2i__get(&co->varnames_inv, name.index, -1); int index = c11_smallmap_n2i__get(&co->varnames_inv, name.index, -1);
if(index >= 0) return index; if(index >= 0) return index;
co->varnames.push_back(name); c11_vector__push(uint16_t, &co->varnames, name.index);
co->nlocals++; co->nlocals++;
index = co->varnames.size() - 1; index = co->varnames.count - 1;
c11_smallmap_n2i__set(&co->varnames_inv, name.index, index); c11_smallmap_n2i__set(&co->varnames_inv, name.index, index);
return index; return index;
} }
@ -127,9 +132,10 @@ int CodeEmitContext::add_const_string(std::string_view key) noexcept{
if(val) { if(val) {
return *val; return *val;
} else { } else {
co->consts.push_back(VAR(key)); // co->consts.push_back(VAR(key));
int index = co->consts.size() - 1; c11_vector__push(PyVar, &co->consts, VAR(key));
key = co->consts.back().obj_get<Str>().sv(); int index = co->consts.count - 1;
key = c11__getitem(PyVar, &co->consts, index).obj_get<Str>().sv();
c11_smallmap_s2n__set(&_co_consts_string_dedup_map, {key.data(), (int)key.size()}, index); c11_smallmap_s2n__set(&_co_consts_string_dedup_map, {key.data(), (int)key.size()}, index);
return index; return index;
} }
@ -137,14 +143,8 @@ int CodeEmitContext::add_const_string(std::string_view key) noexcept{
int CodeEmitContext::add_const(PyVar v) noexcept{ int CodeEmitContext::add_const(PyVar v) noexcept{
assert(!is_type(v, VM::tp_str)); assert(!is_type(v, VM::tp_str));
co->consts.push_back(v); c11_vector__push(PyVar, &co->consts, v);
int index = co->consts.size() - 1; return co->consts.count - 1;
return index;
}
int CodeEmitContext::add_func_decl(FuncDecl_ decl) noexcept{
co->func_decls.push_back(decl);
return co->func_decls.size() - 1;
} }
void CodeEmitContext::emit_store_name(NameScope scope, StrName name, int line) noexcept{ void CodeEmitContext::emit_store_name(NameScope scope, StrName name, int line) noexcept{
@ -340,14 +340,14 @@ bool TupleExpr::emit_store(CodeEmitContext* ctx) {
} }
if(starred_i == -1) { if(starred_i == -1) {
Bytecode& prev = ctx->co->codes.back(); Bytecode* prev = c11__at(Bytecode, &ctx->co->codes, ctx->co->codes.count - 1);
if(prev.op == OP_BUILD_TUPLE && prev.arg == items.size()) { if(prev->op == OP_BUILD_TUPLE && prev->arg == items.size()) {
// build tuple and unpack it is meaningless // build tuple and unpack it is meaningless
ctx->revert_last_emit_(); ctx->revert_last_emit_();
} else { } else {
if(prev.op == OP_FOR_ITER) { if(prev->op == OP_FOR_ITER) {
prev.op = OP_FOR_ITER_UNPACK; prev->op = OP_FOR_ITER_UNPACK;
prev.arg = items.size(); prev->arg = items.size();
} else { } else {
ctx->emit_(OP_UNPACK_SEQUENCE, items.size(), line); ctx->emit_(OP_UNPACK_SEQUENCE, items.size(), line);
} }
@ -543,7 +543,7 @@ void FStringExpr::emit_(CodeEmitContext* ctx) {
void SubscrExpr::emit_(CodeEmitContext* ctx) { void SubscrExpr::emit_(CodeEmitContext* ctx) {
lhs->emit_(ctx); lhs->emit_(ctx);
rhs->emit_(ctx); rhs->emit_(ctx);
Bytecode last_bc = ctx->co->codes.back(); Bytecode last_bc = c11__getitem(Bytecode, &ctx->co->codes, ctx->co->codes.count-1);
if(rhs->is_name() && last_bc.op == OP_LOAD_FAST) { if(rhs->is_name() && last_bc.op == OP_LOAD_FAST) {
ctx->revert_last_emit_(); ctx->revert_last_emit_();
ctx->emit_(OP_LOAD_SUBSCR_FAST, last_bc.arg, line); ctx->emit_(OP_LOAD_SUBSCR_FAST, last_bc.arg, line);
@ -558,7 +558,7 @@ void SubscrExpr::emit_(CodeEmitContext* ctx) {
bool SubscrExpr::emit_store(CodeEmitContext* ctx) { bool SubscrExpr::emit_store(CodeEmitContext* ctx) {
lhs->emit_(ctx); lhs->emit_(ctx);
rhs->emit_(ctx); rhs->emit_(ctx);
Bytecode last_bc = ctx->co->codes.back(); Bytecode last_bc = c11__getitem(Bytecode, &ctx->co->codes, ctx->co->codes.count-1);
if(rhs->is_name() && last_bc.op == OP_LOAD_FAST) { if(rhs->is_name() && last_bc.op == OP_LOAD_FAST) {
ctx->revert_last_emit_(); ctx->revert_last_emit_();
ctx->emit_(OP_STORE_SUBSCR_FAST, last_bc.arg, line); ctx->emit_(OP_STORE_SUBSCR_FAST, last_bc.arg, line);

View File

@ -34,26 +34,26 @@ void pkpy_Exception__stpush(pkpy_Exception* self, pkpy_SourceData_ src, int line
} }
pkpy_Str pkpy_Exception__summary(pkpy_Exception* self){ pkpy_Str pkpy_Exception__summary(pkpy_Exception* self){
pkpy_SStream ss; pk_SStream ss;
pkpy_SStream__ctor(&ss); pk_SStream__ctor(&ss);
if(self->is_re){ if(self->is_re){
pkpy_SStream__write_cstr(&ss, "Traceback (most recent call last):\n"); pk_SStream__write_cstr(&ss, "Traceback (most recent call last):\n");
} }
for(int i=self->stacktrace.count-1; i >= 0; i--) { for(int i=self->stacktrace.count-1; i >= 0; i--) {
pkpy_ExceptionFrame* frame = c11__at(pkpy_ExceptionFrame, &self->stacktrace, i); pkpy_ExceptionFrame* frame = c11__at(pkpy_ExceptionFrame, &self->stacktrace, i);
pkpy_Str s = pkpy_SourceData__snapshot(frame->src, frame->lineno, frame->cursor, pkpy_Str__data(&frame->name)); pkpy_Str s = pkpy_SourceData__snapshot(frame->src, frame->lineno, frame->cursor, pkpy_Str__data(&frame->name));
pkpy_SStream__write_Str(&ss, &s); pk_SStream__write_Str(&ss, &s);
pkpy_Str__dtor(&s); pkpy_Str__dtor(&s);
pkpy_SStream__write_cstr(&ss, "\n"); pk_SStream__write_cstr(&ss, "\n");
} }
const char* name = pkpy_StrName__rmap(self->type); const char* name = pkpy_StrName__rmap(self->type);
pkpy_SStream__write_cstr(&ss, name); pk_SStream__write_cstr(&ss, name);
if(self->msg.size > 0){ if(self->msg.size > 0){
pkpy_SStream__write_cstr(&ss, ": "); pk_SStream__write_cstr(&ss, ": ");
pkpy_SStream__write_Str(&ss, &self->msg); pk_SStream__write_Str(&ss, &self->msg);
} }
return pkpy_SStream__submit(&ss); return pk_SStream__submit(&ss);
} }

View File

@ -115,7 +115,7 @@ bool VM::py_ge(PyVar _0, PyVar _1) {
} }
#define DISPATCH_JUMP_ABSOLUTE(__target) \ #define DISPATCH_JUMP_ABSOLUTE(__target) \
{ \ { \
frame->_ip = &frame->co->codes[__target]; \ frame->_ip = c11__at(Bytecode, &frame->co->codes, __target); \
goto __NEXT_STEP; \ goto __NEXT_STEP; \
} }
@ -136,7 +136,7 @@ PyVar VM::__run_top_frame() {
frame->_ip++; frame->_ip++;
} else if(__internal_exception.type == InternalExceptionType::Handled) { } else if(__internal_exception.type == InternalExceptionType::Handled) {
// HandledException + continue // HandledException + continue
frame->_ip = &frame->co->codes[__internal_exception.arg]; frame->_ip = c11__at(Bytecode, &frame->co->codes, __internal_exception.arg);
__internal_exception = {}; __internal_exception = {};
} else { } else {
// UnhandledException + continue (need_raise = true) // UnhandledException + continue (need_raise = true)
@ -176,7 +176,9 @@ PyVar VM::__run_top_frame() {
POP(); POP();
DISPATCH() DISPATCH()
/*****************************************/ /*****************************************/
case OP_LOAD_CONST: PUSH(frame->co->consts[byte.arg]); DISPATCH() case OP_LOAD_CONST:
PUSH(c11__getitem(PyVar, &frame->co->consts, byte.arg));
DISPATCH()
case OP_LOAD_NONE: PUSH(None); DISPATCH() case OP_LOAD_NONE: PUSH(None); DISPATCH()
case OP_LOAD_TRUE: PUSH(True); DISPATCH() case OP_LOAD_TRUE: PUSH(True); DISPATCH()
case OP_LOAD_FALSE: PUSH(False); DISPATCH() case OP_LOAD_FALSE: PUSH(False); DISPATCH()
@ -185,12 +187,13 @@ PyVar VM::__run_top_frame() {
/*****************************************/ /*****************************************/
case OP_LOAD_ELLIPSIS: PUSH(Ellipsis); DISPATCH() case OP_LOAD_ELLIPSIS: PUSH(Ellipsis); DISPATCH()
case OP_LOAD_FUNCTION: { case OP_LOAD_FUNCTION: {
const FuncDecl_& decl = frame->co->func_decls[byte.arg]; FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg);
PyVar obj; PyVar obj;
if(decl->nested) { if(decl->nested) {
NameDict* captured = frame->_locals.to_namedict(); NameDict* captured = frame->_locals.to_namedict();
obj = new_object<Function>(tp_function, decl, frame->_module, nullptr, captured); obj = new_object<Function>(tp_function, decl, frame->_module, nullptr, captured);
captured->set(decl->code->name, obj); uint16_t name = pkpy_StrName__map2(pkpy_Str__sv(&decl->code->name));
captured->set(name, obj);
} else { } else {
obj = new_object<Function>(tp_function, decl, frame->_module, nullptr, nullptr); obj = new_object<Function>(tp_function, decl, frame->_module, nullptr, nullptr);
} }
@ -201,7 +204,7 @@ PyVar VM::__run_top_frame() {
/*****************************************/ /*****************************************/
case OP_LOAD_FAST: { case OP_LOAD_FAST: {
PyVar _0 = frame->_locals[byte.arg]; PyVar _0 = frame->_locals[byte.arg];
if(_0 == PY_NULL) vm->UnboundLocalError(frame->co->varnames[byte.arg]); if(_0 == PY_NULL) vm->UnboundLocalError(c11__getitem(uint16_t, &frame->co->varnames, byte.arg));
PUSH(_0); PUSH(_0);
} }
DISPATCH() DISPATCH()
@ -311,7 +314,7 @@ PyVar VM::__run_top_frame() {
DISPATCH() DISPATCH()
case OP_LOAD_SUBSCR_FAST: { case OP_LOAD_SUBSCR_FAST: {
PyVar _1 = frame->_locals[byte.arg]; PyVar _1 = frame->_locals[byte.arg];
if(_1 == PY_NULL) vm->UnboundLocalError(frame->co->varnames[byte.arg]); if(_1 == PY_NULL) vm->UnboundLocalError(c11__getitem(uint16_t, &frame->co->varnames, byte.arg));
PyVar _0 = TOP(); // a PyVar _0 = TOP(); // a
auto _ti = _tp_info(_0); auto _ti = _tp_info(_0);
if(_ti->m__getitem__) { if(_ti->m__getitem__) {
@ -376,7 +379,7 @@ PyVar VM::__run_top_frame() {
DISPATCH() DISPATCH()
case OP_STORE_SUBSCR_FAST: { case OP_STORE_SUBSCR_FAST: {
PyVar _2 = frame->_locals[byte.arg]; // b PyVar _2 = frame->_locals[byte.arg]; // b
if(_2 == PY_NULL) vm->UnboundLocalError(frame->co->varnames[byte.arg]); if(_2 == PY_NULL) vm->UnboundLocalError(c11__getitem(uint16_t, &frame->co->varnames, byte.arg));
PyVar _1 = POPX(); // a PyVar _1 = POPX(); // a
PyVar _0 = POPX(); // val PyVar _0 = POPX(); // val
auto _ti = _tp_info(_1); auto _ti = _tp_info(_1);
@ -389,7 +392,7 @@ PyVar VM::__run_top_frame() {
DISPATCH() DISPATCH()
case OP_DELETE_FAST: { case OP_DELETE_FAST: {
PyVar _0 = frame->_locals[byte.arg]; PyVar _0 = frame->_locals[byte.arg];
if(_0 == PY_NULL) vm->UnboundLocalError(frame->co->varnames[byte.arg]); if(_0 == PY_NULL) vm->UnboundLocalError(c11__getitem(uint16_t, &frame->co->varnames, byte.arg));
frame->_locals[byte.arg].set_null(); frame->_locals[byte.arg].set_null();
} }
DISPATCH() DISPATCH()
@ -792,12 +795,12 @@ PyVar VM::__run_top_frame() {
} }
/*****************************************/ /*****************************************/
case OP_FSTRING_EVAL: { case OP_FSTRING_EVAL: {
PyVar _0 = frame->co->consts[byte.arg]; PyVar _0 = c11__getitem(PyVar, &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, frame->_module, frame->_callable, frame->_locals); _0 = vm->_exec(code, frame->_module, frame->_callable, frame->_locals);
delete code; // leak on error CodeObject__delete(code);
PUSH(_0); PUSH(_0);
} }
DISPATCH() DISPATCH()
@ -968,7 +971,7 @@ PyVar VM::__run_top_frame() {
DISPATCH() DISPATCH()
/*****************************************/ /*****************************************/
case OP_IMPORT_PATH: { case OP_IMPORT_PATH: {
PyVar _0 = frame->co->consts[byte.arg]; PyVar _0 = c11__getitem(PyVar, &frame->co->consts, byte.arg);
PUSH(py_import(CAST(Str&, _0))); PUSH(py_import(CAST(Str&, _0)));
} }
DISPATCH() DISPATCH()
@ -1103,7 +1106,7 @@ PyVar VM::__run_top_frame() {
/*****************************************/ /*****************************************/
case OP_FORMAT_STRING: { case OP_FORMAT_STRING: {
PyVar _0 = POPX(); PyVar _0 = POPX();
const Str& spec = CAST(Str&, frame->co->consts[byte.arg]); const Str& spec = CAST(Str&, c11__getitem(PyVar, &frame->co->consts, byte.arg));
PUSH(__format_object(_0, spec)); PUSH(__format_object(_0, spec));
} }
DISPATCH() DISPATCH()

View File

@ -27,32 +27,33 @@ PyVar* Frame::f_closure_try_get(StrName name) {
int Frame::prepare_jump_exception_handler(ValueStack* _s) { 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 = c11__at(BytecodeEx, &co->codes_ex, ip())->iblock;
while(i >= 0) { while(i >= 0) {
if(co->blocks[i].type == CodeBlockType_TRY_EXCEPT) break; CodeBlock* block = c11__at(CodeBlock, &co->blocks, i);
i = co->blocks[i].parent; if(block->type == CodeBlockType_TRY_EXCEPT) break;
i = block->parent;
} }
if(i < 0) return -1; if(i < 0) return -1;
PyVar obj = _s->popx(); // pop exception object PyVar obj = _s->popx(); // pop exception object
UnwindTarget* uw = find_unwind_target(i); UnwindTarget* uw = find_unwind_target(i);
_s->reset(actual_sp_base() + uw->offset); // unwind the stack _s->reset(actual_sp_base() + uw->offset); // unwind the stack
_s->push(obj); // push it back _s->push(obj); // push it back
return co->blocks[i].end; return c11__at(CodeBlock, &co->blocks, i)->end;
} }
int Frame::_exit_block(ValueStack* _s, int i) { int Frame::_exit_block(ValueStack* _s, int i) {
auto type = co->blocks[i].type; CodeBlock* block = c11__at(CodeBlock, &co->blocks, i);
if(type == CodeBlockType_FOR_LOOP) { if(block->type == CodeBlockType_FOR_LOOP) {
_s->pop(); // pop the iterator _s->pop(); // pop the iterator
} else if(type == CodeBlockType_CONTEXT_MANAGER) { } else if(block->type == CodeBlockType_CONTEXT_MANAGER) {
_s->pop(); _s->pop();
} }
return co->blocks[i].parent; return block->parent;
} }
void Frame::prepare_jump_break(ValueStack* _s, int target) { void Frame::prepare_jump_break(ValueStack* _s, int target) {
int i = co->lines[ip()].iblock; int i = c11__at(BytecodeEx, &co->codes_ex, ip())->iblock;
if(target >= co->codes.size()) { if(target >= co->codes.count) {
while(i >= 0) while(i >= 0)
i = _exit_block(_s, i); i = _exit_block(_s, i);
} else { } else {
@ -61,7 +62,7 @@ void Frame::prepare_jump_break(ValueStack* _s, int target) {
// _ = 0 // _ = 0
// # if there is no op here, the block check will fail // # if there is no op here, the block check will fail
// while i: --i // while i: --i
int next_block = co->lines[target].iblock; int next_block = c11__at(BytecodeEx, &co->codes_ex, target)->iblock;
while(i >= 0 && i != next_block) while(i >= 0 && i != next_block)
i = _exit_block(_s, i); i = _exit_block(_s, i);
assert(i == next_block); assert(i == next_block);
@ -69,7 +70,7 @@ void Frame::prepare_jump_break(ValueStack* _s, int target) {
} }
void Frame::set_unwind_target(PyVar* _sp) { void Frame::set_unwind_target(PyVar* _sp) {
int iblock = co->lines[ip()].iblock; int iblock = c11__at(BytecodeEx, &co->codes_ex, ip())->iblock;
UnwindTarget* existing = find_unwind_target(iblock); UnwindTarget* existing = find_unwind_target(iblock);
if(existing) { if(existing) {
existing->offset = _sp - actual_sp_base(); existing->offset = _sp - actual_sp_base();

View File

@ -1,6 +1,7 @@
#include "pocketpy/interpreter/vm.hpp" #include "pocketpy/interpreter/vm.hpp"
#include "pocketpy/common/memorypool.h" #include "pocketpy/common/memorypool.h"
#include "pocketpy/objects/base.h" #include "pocketpy/objects/base.h"
#include "pocketpy/objects/codeobject.h"
#include "pocketpy/objects/public.h" #include "pocketpy/objects/public.h"
#include <cstddef> #include <cstddef>
@ -209,7 +210,7 @@ PyVar VM::exec(std::string_view source, Str filename, CompileMode mode, PyObject
#endif #endif
code = compile(source, filename, mode); code = compile(source, filename, mode);
PyVar retval = _exec(code, _module); PyVar retval = _exec(code, _module);
delete code; // leak if exception occurs CodeObject__delete(code);
return retval; return retval;
} catch(TopLevelException e) { } catch(TopLevelException e) {
stderr_write(e.summary() + "\n"); stderr_write(e.summary() + "\n");
@ -221,7 +222,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; CodeObject__delete(code);
callstack.clear(); callstack.clear();
s_data.clear(); s_data.clear();
return nullptr; return nullptr;
@ -419,11 +420,12 @@ PyObject* VM::py_import(Str path, bool throw_err) {
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); CodeObject* code = compile(source, filename, EXEC_MODE);
_exec(code, new_mod); _exec(code, new_mod);
delete code; // leak if exception occurs CodeObject__delete(code);
return new_mod; return new_mod;
} }
VM::~VM() { VM::~VM() {
PK_DECREF(__dynamic_func_decl);
// destroy all objects // destroy all objects
pk_ManagedHeap__dtor(&heap); pk_ManagedHeap__dtor(&heap);
// clear everything // clear everything
@ -628,11 +630,14 @@ PyVar VM::__py_exec_internal(const CodeObject* code, PyVar globals, PyVar locals
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);
CodeObject__delete(code);
} }
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); PyVar retval = __py_exec_internal(code, globals, locals);
CodeObject__delete(code);
return retval;
} }
PyVar VM::__format_object(PyVar obj, Str spec) { PyVar VM::__format_object(PyVar obj, Str spec) {
@ -752,9 +757,11 @@ static std::string _opcode_argstr(VM* vm, int i, Bytecode byte, const CodeObject
switch(byte.op) { switch(byte.op) {
case OP_LOAD_CONST: case OP_LOAD_CONST:
case OP_FORMAT_STRING: case OP_FORMAT_STRING:
case OP_IMPORT_PATH: case OP_IMPORT_PATH: {
if(vm != nullptr) ss << " (" << vm->py_repr(co->consts[byte.arg]) << ")"; PyVar obj = c11__getitem(PyVar, &co->consts, byte.arg);
if(vm != nullptr) ss << " (" << vm->py_repr(obj) << ")";
break; break;
}
case OP_LOAD_NAME: case OP_LOAD_NAME:
case OP_LOAD_GLOBAL: case OP_LOAD_GLOBAL:
case OP_LOAD_NONLOCAL: case OP_LOAD_NONLOCAL:
@ -773,8 +780,16 @@ static std::string _opcode_argstr(VM* vm, int i, Bytecode byte, const CodeObject
case OP_DELETE_FAST: case OP_DELETE_FAST:
case OP_FOR_ITER_STORE_FAST: case OP_FOR_ITER_STORE_FAST:
case OP_LOAD_SUBSCR_FAST: case OP_LOAD_SUBSCR_FAST:
case OP_STORE_SUBSCR_FAST: ss << " (" << co->varnames[byte.arg].sv() << ")"; break; case OP_STORE_SUBSCR_FAST:{
case OP_LOAD_FUNCTION: ss << " (" << co->func_decls[byte.arg]->code->name << ")"; break; StrName name = c11__getitem(StrName, &co->varnames, byte.arg);
ss << " (" << name.sv() << ")";
break;
}
case OP_LOAD_FUNCTION: {
const FuncDecl* decl = c11__getitem(FuncDecl*, &co->func_decls, byte.arg);
ss << " (" << pkpy_Str__data(&decl->code->name) << ")";
break;
}
} }
return ss.str().str(); return ss.str().str();
} }
@ -786,22 +801,23 @@ 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.count; i++) {
Bytecode byte = co->codes[i]; Bytecode* bc = c11__at(Bytecode, &co->codes, i);
if(Bytecode__is_forward_jump(&byte)) { if(Bytecode__is_forward_jump(bc)) {
jumpTargets.push_back((int16_t)byte.arg + i); jumpTargets.push_back((int16_t)bc->arg + i);
} }
} }
SStream ss; SStream ss;
int prev_line = -1; int prev_line = -1;
for(int i = 0; i < co->codes.size(); i++) { for(int i = 0; i < co->codes.count; i++) {
const Bytecode& byte = co->codes[i]; Bytecode byte = c11__getitem(Bytecode, &co->codes, i);
Str line = std::to_string(co->lines[i].lineno); BytecodeEx ex = c11__getitem(BytecodeEx, &co->codes_ex, i);
if(co->lines[i].lineno == prev_line) Str line = std::to_string(ex.lineno);
if(ex.lineno == prev_line)
line = ""; line = "";
else { else {
if(prev_line != -1) ss << "\n"; if(prev_line != -1) ss << "\n";
prev_line = co->lines[i].lineno; prev_line = ex.lineno;
} }
std::string pointer; std::string pointer;
@ -812,16 +828,17 @@ Str VM::disassemble(CodeObject* co) {
} }
ss << pad(line, 8) << pointer << pad(std::to_string(i), 3); ss << pad(line, 8) << pointer << pad(std::to_string(i), 3);
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(ex.is_virtual) bc_name += '*';
ss << " " << pad(bc_name, 25) << " "; ss << " " << pad(bc_name, 25) << " ";
std::string argStr = _opcode_argstr(this, i, byte, co); 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.count - 1) ss << '\n';
} }
for(auto& decl: co->func_decls) { c11_vector__foreach(FuncDecl*, &co->func_decls, it) {
FuncDecl* decl = *it;
ss << "\n\n" ss << "\n\n"
<< "Disassembly of " << decl->code->name << ":\n"; << "Disassembly of " << pkpy_Str__data(&decl->code->name) << ":\n";
ss << disassemble(decl->code); ss << disassemble(decl->code);
} }
ss << "\n"; ss << "\n";
@ -986,21 +1003,22 @@ 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; const CodeObject* co = decl->code;
int decl_argc = decl->args.size(); int decl_argc = decl->args.count;
if(args.size() < decl_argc) { if(args.size() < decl_argc) {
vm->TypeError(_S(co->name, "() takes ", decl_argc, " positional arguments but ", args.size(), " were given")); vm->TypeError(_S(pkpy_Str__data(&co->name), "() takes ", decl_argc, " positional arguments but ", args.size(), " were given"));
} }
int i = 0; int i = 0;
// prepare args // prepare args
std::memset(buffer, 0, co->nlocals * sizeof(PyVar)); std::memset(buffer, 0, co->nlocals * sizeof(PyVar));
for(int index: decl->args) c11_vector__foreach(int, &decl->args, index) {
buffer[index] = args[i++]; buffer[*index] = args[i++];
}
// prepare kwdefaults // prepare kwdefaults
c11_vector__foreach(FuncDecl::KwArg, &decl->kwargs, kv) { c11_vector__foreach(FuncDeclKwArg, &decl->kwargs, kv) {
buffer[kv->index] = kv->value; buffer[kv->index] = kv->value;
} }
@ -1011,11 +1029,11 @@ void VM::__prepare_py_call(PyVar* buffer, ArgsView args, ArgsView kwargs, const
i += vargs.size(); i += vargs.size();
} else { } else {
// kwdefaults override // kwdefaults override
c11_vector__foreach(FuncDecl::KwArg, &decl->kwargs, kv) { c11_vector__foreach(FuncDeclKwArg, &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", " (", pkpy_Str__data(&decl->code->name), ')'));
} }
PyVar vkwargs; PyVar vkwargs;
@ -1035,7 +1053,7 @@ void VM::__prepare_py_call(PyVar* buffer, ArgsView args, ArgsView kwargs, const
} else { } else {
// otherwise, set as **kwargs if possible // otherwise, set as **kwargs if possible
if(!vkwargs) { if(!vkwargs) {
TypeError(_S(key.escape(), " is an invalid keyword argument for ", co->name, "()")); TypeError(_S(key.escape(), " is an invalid keyword argument for ", pkpy_Str__data(&co->name), "()"));
} else { } else {
Dict& dict = _CAST(Dict&, vkwargs); Dict& dict = _CAST(Dict&, vkwargs);
dict.set(this, VAR(key.sv()), kwargs[j + 1]); dict.set(this, VAR(key.sv()), kwargs[j + 1]);
@ -1085,14 +1103,15 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
_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.count){
TypeError(_S(co->name, TypeError(pk_format(
"() takes ", "{} takes {} positional arguments but {} were given",
fn.decl->args.size(), &co->name, fn.decl->args.count, args.size()
" positional arguments but ", ));
args.size(), }
" were given")); if(!kwargs.empty()){
if(!kwargs.empty()) TypeError(_S(co->name, "() takes no keyword arguments")); TypeError(pk_format("{} takes no keyword arguments", &co->name));
}
// [callable, <self>, args..., local_vars...] // [callable, <self>, args..., local_vars...]
// ^p0 ^p1 ^_sp // ^p0 ^p1 ^_sp
s_data.reset(_base + co->nlocals); s_data.reset(_base + co->nlocals);
@ -1100,14 +1119,15 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
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.count){
TypeError(_S(co->name, TypeError(pk_format(
"() takes ", "{} takes {} positional arguments but {} were given",
fn.decl->args.size(), &co->name, fn.decl->args.count, args.size()
" positional arguments but ", ));
args.size(), }
" were given")); if(!kwargs.empty()){
if(!kwargs.empty()) TypeError(_S(co->name, "() takes no keyword arguments")); TypeError(pk_format("{} takes no keyword arguments", &co->name));
}
s_data.reset(p0); s_data.reset(p0);
return None; return None;
case FuncType_GENERATOR: case FuncType_GENERATOR:
@ -1385,9 +1405,10 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native
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* code = compile(source, "<bind>", EXEC_MODE); CodeObject* code = compile(source, "<bind>", EXEC_MODE);
assert(code->func_decls.size() == 1); assert(code->func_decls.count == 1);
FuncDecl_ decl = code->func_decls[0]; FuncDecl_ decl = c11__getitem(FuncDecl_, &code->func_decls, 0);
delete code; // may leak if exception occurs c11_vector__clear(&code->func_decls); // move decl
CodeObject__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();
@ -1396,7 +1417,10 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native
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_FUNCTION: break; case BindType_FUNCTION: break;
} }
if(obj != nullptr) obj->attr().set(decl->code->name, f_obj); if(obj != nullptr){
StrName name = pkpy_Str__data(&decl->code->name);
obj->attr().set(name, f_obj);
}
return f_obj; return f_obj;
} }
@ -1459,9 +1483,9 @@ void VM::__raise_exc(bool re_raise) {
int actual_ip = frame->ip(); int actual_ip = frame->ip();
if(e._ip_on_error >= 0 && e._code_on_error == (void*)frame->co) actual_ip = e._ip_on_error; if(e._ip_on_error >= 0 && e._code_on_error == (void*)frame->co) actual_ip = e._ip_on_error;
int current_line = frame->co->lines[actual_ip].lineno; // current line int current_line = c11__at(BytecodeEx, &frame->co->codes_ex, actual_ip)->lineno;
const char* current_f_name = frame->co->name.c_str(); // current function name const char* current_f_name = pkpy_Str__data(&frame->co->name); // current function name
if(frame->_callable == nullptr) current_f_name = ""; // not in a function if(frame->_callable == nullptr) current_f_name = ""; // not in a function
e.stpush(frame->co->src, current_line, nullptr, current_f_name); e.stpush(frame->co->src, current_line, nullptr, current_f_name);
if(next_ip >= 0) { if(next_ip >= 0) {
@ -1802,13 +1826,13 @@ void VM::__breakpoint() {
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, 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; CodeObject__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, frame_0->_module, frame_0->_callable, frame_0->_locals); vm->_exec(code, frame_0->_module, frame_0->_callable, frame_0->_locals);
delete code; CodeObject__delete(code);
} }
continue; continue;
} }
@ -1822,7 +1846,7 @@ PyVar PyObject::attr(StrName name) const{
/**************************************************************************/ /**************************************************************************/
void Function::_gc_mark(VM* vm) const { void Function::_gc_mark(VM* vm) const {
decl->_gc_mark(vm); FuncDecl__gc_mark(decl);
if(_closure) { if(_closure) {
_closure->apply([](StrName _, PyVar obj, void* userdata) { _closure->apply([](StrName _, PyVar obj, void* userdata) {
VM* vm = (VM*)userdata; VM* vm = (VM*)userdata;
@ -1832,13 +1856,28 @@ void Function::_gc_mark(VM* vm) const {
} }
void NativeFunc::_gc_mark(VM* vm) const { void NativeFunc::_gc_mark(VM* vm) const {
if(decl) decl->_gc_mark(vm); if(decl){
FuncDecl__gc_mark(decl);
}
} }
void FuncDecl::_gc_mark(VM* vm) const { extern "C"{
code->_gc_mark(vm); void FuncDecl__gc_mark(const FuncDecl *self){
c11_vector__foreach(FuncDecl::KwArg, &kwargs, kv) { VM* vm = (VM*)pkpy_g.vm;
vm->obj_gc_mark(kv->value); CodeObject__gc_mark(self->code);
c11_vector__foreach(FuncDeclKwArg, &self->kwargs, kv) {
vm->obj_gc_mark(kv->value);
}
}
void CodeObject__gc_mark(const CodeObject* self) {
VM* vm = (VM*)pkpy_g.vm;
c11_vector__foreach(PyVar, &self->consts, v) {
vm->obj_gc_mark(*v);
}
c11_vector__foreach(FuncDecl*, &self->func_decls, decl) {
FuncDecl__gc_mark(*decl);
}
} }
} }
@ -1880,7 +1919,7 @@ void Super::_gc_mark(VM* vm) const { vm->obj_gc_mark(first); }
void Frame::_gc_mark(VM* vm) const { void Frame::_gc_mark(VM* vm) const {
vm->obj_gc_mark(_module); vm->obj_gc_mark(_module);
co->_gc_mark(vm); CodeObject__gc_mark(co);
// Frame could be stored in a generator, so mark _callable for safety // Frame could be stored in a generator, so mark _callable for safety
vm->obj_gc_mark(_callable); vm->obj_gc_mark(_callable);
} }
@ -1924,11 +1963,4 @@ void Dict::_gc_mark(VM* vm) const {
}); });
} }
void CodeObject::_gc_mark(VM* vm) const {
for(PyVar v: consts)
vm->obj_gc_mark(v);
for(auto& decl: func_decls)
decl->_gc_mark(vm);
}
} // namespace pkpy } // namespace pkpy

View File

@ -108,7 +108,7 @@ void add_module_json(VM* vm) {
} }
CodeObject* code = vm->compile(sv, "<json>", JSON_MODE); CodeObject* code = vm->compile(sv, "<json>", JSON_MODE);
PyVar retval = vm->_exec(code, vm->callstack.top()._module); PyVar retval = vm->_exec(code, vm->callstack.top()._module);
delete code; // leak on error CodeObject__delete(code);
return retval; return retval;
}); });
@ -238,7 +238,7 @@ void add_module_dis(VM* vm) {
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; if(need_delete) CodeObject__delete(code);
return vm->None; return vm->None;
}); });
} }
@ -252,7 +252,7 @@ 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 CodeObject__delete(code);
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

View File

@ -1,5 +1,6 @@
#include "pocketpy/objects/codeobject.h" #include "pocketpy/objects/codeobject.h"
#include "pocketpy/common/utils.h" #include "pocketpy/common/utils.h"
#include <stdint.h>
void Bytecode__set_signed_arg(Bytecode* self, int arg) { void Bytecode__set_signed_arg(Bytecode* self, int arg) {
if(arg < INT16_MIN || arg > INT16_MAX) { if(arg < INT16_MIN || arg > INT16_MAX) {
@ -11,3 +12,86 @@ void Bytecode__set_signed_arg(Bytecode* self, int arg) {
bool Bytecode__is_forward_jump(const Bytecode* self) { bool Bytecode__is_forward_jump(const Bytecode* self) {
return self->op >= OP_JUMP_FORWARD && self->op <= OP_LOOP_BREAK; return self->op >= OP_JUMP_FORWARD && self->op <= OP_LOOP_BREAK;
} }
FuncDecl_ FuncDecl__rcnew(pkpy_SourceData_ src, c11_string name){
FuncDecl* self = malloc(sizeof(FuncDecl));
self->rc.count = 1;
self->rc.dtor = (void (*)(void*))FuncDecl__dtor;
self->code = CodeObject__new(src, name);
c11_vector__ctor(&self->args, sizeof(int));
c11_vector__ctor(&self->kwargs, sizeof(FuncDeclKwArg));
self->starred_arg = -1;
self->starred_kwarg = -1;
self->nested = false;
self->docstring = NULL;
self->type = FuncType_UNSET;
c11_smallmap_n2i__ctor(&self->kw_to_index);
return self;
}
void FuncDecl__dtor(FuncDecl* self){
CodeObject__delete(self->code);
c11_vector__dtor(&self->args);
c11_vector__dtor(&self->kwargs);
c11_smallmap_n2i__dtor(&self->kw_to_index);
}
void FuncDecl__add_kwarg(FuncDecl* self, int index, uint16_t key, const PyVar* value){
c11_smallmap_n2i__set(&self->kw_to_index, key, index);
FuncDeclKwArg item = {index, key, *value};
c11_vector__push(FuncDeclKwArg, &self->kwargs, item);
}
CodeObject* CodeObject__new(pkpy_SourceData_ src, c11_string name){
CodeObject* self = malloc(sizeof(CodeObject));
self->src = src; PK_INCREF(src);
pkpy_Str__ctor2(&self->name, name.data, name.size);
c11_vector__ctor(&self->codes, sizeof(Bytecode));
c11_vector__ctor(&self->codes_ex, sizeof(BytecodeEx));
c11_vector__ctor(&self->consts, sizeof(PyVar));
c11_vector__ctor(&self->varnames, sizeof(uint16_t));
self->nlocals = 0;
c11_smallmap_n2i__ctor(&self->varnames_inv);
c11_smallmap_n2i__ctor(&self->labels);
c11_vector__ctor(&self->blocks, sizeof(CodeBlock));
c11_vector__ctor(&self->func_decls, sizeof(FuncDecl_));
self->start_line = -1;
self->end_line = -1;
CodeBlock root_block = {CodeBlockType_NO_BLOCK, -1, 0, -1, -1};
c11_vector__push(CodeBlock, &self->blocks, root_block);
return self;
}
void CodeObject__delete(CodeObject* self){
PK_DECREF(self->src);
pkpy_Str__dtor(&self->name);
c11_vector__dtor(&self->codes);
c11_vector__dtor(&self->codes_ex);
c11_vector__dtor(&self->consts);
c11_vector__dtor(&self->varnames);
c11_smallmap_n2i__dtor(&self->varnames_inv);
c11_smallmap_n2i__dtor(&self->labels);
c11_vector__dtor(&self->blocks);
for(int i=0; i<self->func_decls.count; i++){
FuncDecl_ decl = c11__getitem(FuncDecl_, &self->func_decls, i);
PK_DECREF(decl);
}
c11_vector__dtor(&self->func_decls);
free(self);
}

View File

@ -2,6 +2,7 @@
#include "pocketpy/common/_generated.h" #include "pocketpy/common/_generated.h"
#include "pocketpy/common/refcount.h"
#include "pocketpy/modules/array2d.hpp" #include "pocketpy/modules/array2d.hpp"
#include "pocketpy/modules/base64.hpp" #include "pocketpy/modules/base64.hpp"
#include "pocketpy/modules/csv.hpp" #include "pocketpy/modules/csv.hpp"
@ -12,6 +13,7 @@
#include "pocketpy/modules/random.hpp" #include "pocketpy/modules/random.hpp"
#include "pocketpy/modules/modules.hpp" #include "pocketpy/modules/modules.hpp"
#include "pocketpy/objects/base.h" #include "pocketpy/objects/base.h"
#include "pocketpy/objects/codeobject.h"
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
@ -1692,15 +1694,16 @@ void VM::__post_init_builtin_types() {
try { try {
// initialize dummy func_decl for exec/eval // initialize dummy func_decl for exec/eval
CodeObject* code = compile("def _(): pass", "<dynamic>", EXEC_MODE); CodeObject* code = compile("def _(): pass", "<dynamic>", EXEC_MODE);
__dynamic_func_decl = code->func_decls[0]; __dynamic_func_decl = c11__getitem(FuncDecl_, &code->func_decls, 0);
delete code; // may leak on error PK_INCREF(__dynamic_func_decl);
CodeObject__delete(code);
// initialize builtins // initialize builtins
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 CodeObject__delete(code);
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 CodeObject__delete(code);
} 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;

View File

@ -1,3 +1,4 @@
#include "pocketpy/objects/codeobject.h"
#ifndef PK_NO_EXPORT_C_API #ifndef PK_NO_EXPORT_C_API
#include "pocketpy/pocketpy.hpp" #include "pocketpy/pocketpy.hpp"
@ -62,7 +63,7 @@ bool pkpy_exec(pkpy_vm* vm_handle, const char* source) {
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 CodeObject__delete(code);
) )
return res != nullptr; return res != nullptr;
} }
@ -79,7 +80,7 @@ bool pkpy_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, i
} }
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 CodeObject__delete(code); // TODO: _exec may raise, so code may leak
) )
return res != nullptr; return res != nullptr;
} }
@ -419,10 +420,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* code = vm->compile(source, "<eval>", EVAL_MODE);
PyVar ret = vm->_exec(co, vm->_main); PyVar ret = vm->_exec(code, vm->_main);
vm->s_data.push(ret); vm->s_data.push(ret);
delete co; // TODO: _exec may raise, so code may leak CodeObject__delete(code);
) )
return true; return true;
} }