mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
Compare commits
13 Commits
62420dade1
...
5be3300554
Author | SHA1 | Date | |
---|---|---|---|
|
5be3300554 | ||
|
f53ae5e459 | ||
|
6c46705e98 | ||
|
455aa576e5 | ||
|
4a5f74b2d2 | ||
|
a55d3a5340 | ||
|
773a05e25c | ||
|
c4897ea0fb | ||
|
0963929a30 | ||
|
23b523b788 | ||
|
14a01c0e6d | ||
|
a03a3bdbf8 | ||
|
3610e87244 |
@ -5,8 +5,8 @@ python prebuild.py
|
||||
SRC=$(find src/ -name "*.c")
|
||||
|
||||
FLAGS="-std=c11 -lm -Iinclude -O0 -Wfatal-errors -g -DDEBUG -DPK_ENABLE_OS=1"
|
||||
# SANITIZE_FLAGS="-fsanitize=address,leak,undefined"
|
||||
SANITIZE_FLAGS=""
|
||||
SANITIZE_FLAGS="-fsanitize=address,leak,undefined"
|
||||
# SANITIZE_FLAGS=""
|
||||
|
||||
echo "Compiling C files..."
|
||||
clang $FLAGS $SANITIZE_FLAGS $SRC src2/main.c -o main
|
||||
|
@ -43,8 +43,8 @@
|
||||
|
||||
/*************** internal settings ***************/
|
||||
|
||||
// This is the maximum size of the value stack in PyVar units
|
||||
// The actual size in bytes equals `sizeof(PyVar) * PK_VM_STACK_SIZE`
|
||||
// This is the maximum size of the value stack in py_TValue units
|
||||
// The actual size in bytes equals `sizeof(py_TValue) * PK_VM_STACK_SIZE`
|
||||
#define PK_VM_STACK_SIZE 16384
|
||||
|
||||
// This is the maximum number of local variables in a function
|
||||
|
@ -14,6 +14,7 @@ typedef uint16_t StrName;
|
||||
uint16_t pk_StrName__map(const char*);
|
||||
uint16_t pk_StrName__map2(c11_string);
|
||||
const char* pk_StrName__rmap(uint16_t index);
|
||||
c11_string pk_StrName__rmap2(uint16_t index);
|
||||
|
||||
void pk_StrName__initialize();
|
||||
void pk_StrName__finalize();
|
||||
|
@ -1,141 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/compiler/expr.hpp"
|
||||
#include "pocketpy/objects/error.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
struct Compiler;
|
||||
typedef Error* (Compiler::*PrattCallback)() noexcept;
|
||||
|
||||
struct PrattRule {
|
||||
PrattCallback prefix;
|
||||
PrattCallback infix;
|
||||
Precedence precedence;
|
||||
};
|
||||
|
||||
struct Compiler {
|
||||
PK_ALWAYS_PASS_BY_POINTER(Compiler)
|
||||
|
||||
static PrattRule rules[TK__COUNT__];
|
||||
|
||||
Lexer lexer;
|
||||
vector<CodeEmitContext> contexts;
|
||||
VM* vm;
|
||||
bool unknown_global_scope; // for eval/exec() call
|
||||
// for parsing token stream
|
||||
int __i = 0;
|
||||
|
||||
const Token& tk(int i) const noexcept{ return lexer.nexts[i]; }
|
||||
const Token& prev() const noexcept{ return tk(__i - 1); }
|
||||
const Token& curr() const noexcept{ return tk(__i); }
|
||||
const Token& next() const noexcept{ return tk(__i + 1); }
|
||||
|
||||
const Token& err() const noexcept{
|
||||
if(__i >= lexer.nexts.size()) return prev();
|
||||
return curr();
|
||||
}
|
||||
|
||||
void advance(int delta = 1) noexcept{
|
||||
__i += delta;
|
||||
#if PK_DEBUG_COMPILER
|
||||
if(__i>=0 && __i<lexer.nexts.size()){
|
||||
printf("%s:%d %s %s\n",
|
||||
lexer.src.filename().c_str(),
|
||||
curr().line,
|
||||
pk_TokenSymbols(curr().type),
|
||||
curr().str().escape().c_str()
|
||||
);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
CodeEmitContext* ctx() noexcept{ return &contexts.back(); }
|
||||
CompileMode mode() const noexcept{ return lexer.src->mode; }
|
||||
|
||||
NameScope name_scope() const noexcept;
|
||||
CodeObject* push_global_context() noexcept;
|
||||
FuncDecl_ push_f_context(c11_string name, int* out_index) noexcept;
|
||||
|
||||
static void init_pratt_rules() noexcept;
|
||||
|
||||
bool match(TokenIndex expected) noexcept;
|
||||
bool match_end_stmt() noexcept;
|
||||
bool match_newlines(bool* need_more_lines = NULL) noexcept;
|
||||
/*************************************************/
|
||||
[[nodiscard]] Error* EXPR() noexcept{ return parse_expression(PREC_LOWEST + 1); }
|
||||
[[nodiscard]] Error* EXPR_TUPLE(bool allow_slice = false) noexcept;
|
||||
[[nodiscard]] Error* EXPR_VARS() noexcept; // special case for `for loop` and `comp`
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T* make_expr(Args&&... args) noexcept{
|
||||
static_assert(sizeof(T) <= kPoolExprBlockSize);
|
||||
static_assert(std::is_base_of_v<Expr, T>);
|
||||
void* p = PoolExpr_alloc();
|
||||
T* expr = new (p) T(std::forward<Args>(args)...);
|
||||
expr->line = prev().line;
|
||||
return expr;
|
||||
}
|
||||
|
||||
[[nodiscard]] Error* consume_comp(Opcode op0, Opcode op1) noexcept;
|
||||
[[nodiscard]] Error* pop_context() noexcept;
|
||||
|
||||
Error* exprLiteral() noexcept;
|
||||
Error* exprLong() noexcept;
|
||||
Error* exprImag() noexcept;
|
||||
Error* exprBytes() noexcept;
|
||||
Error* exprFString() noexcept;
|
||||
Error* exprLambda() noexcept;
|
||||
Error* exprOr() noexcept;
|
||||
Error* exprAnd() noexcept;
|
||||
Error* exprTernary() noexcept;
|
||||
Error* exprBinaryOp() noexcept;
|
||||
Error* exprNot() noexcept;
|
||||
Error* exprUnaryOp() noexcept;
|
||||
Error* exprGroup() noexcept;
|
||||
Error* exprList() noexcept;
|
||||
Error* exprMap() noexcept;
|
||||
Error* exprCall() noexcept;
|
||||
Error* exprName() noexcept;
|
||||
Error* exprAttrib() noexcept;
|
||||
Error* exprSlice0() noexcept;
|
||||
Error* exprSlice1() noexcept;
|
||||
Error* exprSubscr() noexcept;
|
||||
Error* exprLiteral0() noexcept;
|
||||
|
||||
bool is_expression(bool allow_slice = false) noexcept;
|
||||
|
||||
[[nodiscard]] Error* compile_block_body(PrattCallback callback = NULL) noexcept;
|
||||
[[nodiscard]] Error* compile_normal_import() noexcept;
|
||||
[[nodiscard]] Error* compile_from_import() noexcept;
|
||||
[[nodiscard]] Error* parse_expression(int precedence, bool allow_slice = false) noexcept;
|
||||
[[nodiscard]] Error* compile_if_stmt() noexcept;
|
||||
[[nodiscard]] Error* compile_while_loop() noexcept;
|
||||
[[nodiscard]] Error* compile_for_loop() noexcept;
|
||||
[[nodiscard]] Error* compile_try_except() noexcept;
|
||||
[[nodiscard]] Error* compile_decorated() noexcept;
|
||||
|
||||
[[nodiscard]] Error* try_compile_assignment(bool* is_assign) noexcept;
|
||||
[[nodiscard]] Error* compile_stmt() noexcept;
|
||||
[[nodiscard]] Error* consume_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_class(int decorators = 0) noexcept;
|
||||
|
||||
PyVar to_object(const TokenValue& value) noexcept;
|
||||
|
||||
[[nodiscard]] Error* read_literal(PyVar* out) noexcept;
|
||||
|
||||
[[nodiscard]] Error* SyntaxError(const char* msg = "invalid syntax", ...) noexcept;
|
||||
[[nodiscard]] Error* IndentationError(const char* msg) noexcept{ return lexer._error(false, "IndentationError", msg, {}); }
|
||||
[[nodiscard]] Error* NeedMoreLines() noexcept{
|
||||
return lexer._error(false, "NeedMoreLines", "", {}, (i64)ctx()->is_compiling_class);
|
||||
}
|
||||
|
||||
public:
|
||||
Compiler(VM* vm, std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope = false) noexcept;
|
||||
[[nodiscard]] Error* compile(CodeObject** out) noexcept;
|
||||
~Compiler();
|
||||
};
|
||||
|
||||
} // namespace pkpy
|
@ -1,60 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#include "pocketpy/common/strname.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct pk_CodeEmitContext{
|
||||
CodeObject* co; // 1 CodeEmitContext <=> 1 CodeObject*
|
||||
FuncDecl* func; // optional, weakref
|
||||
int level;
|
||||
int curr_iblock;
|
||||
bool is_compiling_class;
|
||||
c11_vector/*T=Expr* */ s_expr;
|
||||
c11_vector/*T=StrName*/ global_names;
|
||||
c11_smallmap_s2n co_consts_string_dedup_map;
|
||||
} pk_CodeEmitContext;
|
||||
|
||||
typedef struct pk_Expr pk_Expr;
|
||||
|
||||
void pk_CodeEmitContext__ctor(pk_CodeEmitContext* self, CodeObject* co, FuncDecl* func, int level);
|
||||
void pk_CodeEmitContext__dtor(pk_CodeEmitContext* self);
|
||||
|
||||
int pk_CodeEmitContext__get_loop(pk_CodeEmitContext* self);
|
||||
CodeBlock* pk_CodeEmitContext__enter_block(pk_CodeEmitContext* self, CodeBlockType type);
|
||||
void pk_CodeEmitContext__exit_block(pk_CodeEmitContext* self);
|
||||
int pk_CodeEmitContext__emit_(pk_CodeEmitContext* self, Opcode opcode, uint16_t arg, int line);
|
||||
int pk_CodeEmitContext__emit_virtual(pk_CodeEmitContext* self, Opcode opcode, uint16_t arg, int line);
|
||||
void pk_CodeEmitContext__revert_last_emit_(pk_CodeEmitContext* self);
|
||||
int pk_CodeEmitContext__emit_int(pk_CodeEmitContext* self, int64_t value, int line);
|
||||
void pk_CodeEmitContext__patch_jump(pk_CodeEmitContext* self, int index);
|
||||
bool pk_CodeEmitContext__add_label(pk_CodeEmitContext* self, StrName name);
|
||||
int pk_CodeEmitContext__add_varname(pk_CodeEmitContext* self, StrName name);
|
||||
int pk_CodeEmitContext__add_const(pk_CodeEmitContext* self, py_Ref);
|
||||
int pk_CodeEmitContext__add_const_string(pk_CodeEmitContext* self, c11_string);
|
||||
void pk_CodeEmitContext__emit_store_name(pk_CodeEmitContext* self, NameScope scope, StrName name, int line);
|
||||
void pk_CodeEmitContext__try_merge_for_iter_store(pk_CodeEmitContext* self, int);
|
||||
|
||||
// emit top -> pop -> delete
|
||||
void pk_CodeEmitContext__s_emit_top(pk_CodeEmitContext*);
|
||||
// push
|
||||
void pk_CodeEmitContext__s_push(pk_CodeEmitContext*, pk_Expr*);
|
||||
// top
|
||||
pk_Expr* pk_CodeEmitContext__s_top(pk_CodeEmitContext*);
|
||||
// size
|
||||
int pk_CodeEmitContext__s_size(pk_CodeEmitContext*);
|
||||
// pop -> delete
|
||||
void pk_CodeEmitContext__s_pop(pk_CodeEmitContext*);
|
||||
// pop move
|
||||
pk_Expr* pk_CodeEmitContext__s_popx(pk_CodeEmitContext*);
|
||||
// clean
|
||||
void pk_CodeEmitContext__s_clean(pk_CodeEmitContext*);
|
||||
// emit decorators
|
||||
void pk_CodeEmitContext__s_emit_decorators(pk_CodeEmitContext*, int count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,151 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "pocketpy/common/memorypool.h"
|
||||
#include "pocketpy/compiler/lexer.h"
|
||||
#include "pocketpy/common/strname.h"
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct pk_Expr pk_Expr;
|
||||
typedef struct pk_CodeEmitContext pk_CodeEmitContext;
|
||||
|
||||
typedef struct pk_ExprVt{
|
||||
void (*dtor)(pk_Expr*);
|
||||
/* reflections */
|
||||
bool is_literal;
|
||||
bool is_json_object;
|
||||
bool is_name;
|
||||
bool is_tuple;
|
||||
bool is_attrib;
|
||||
bool is_subscr;
|
||||
bool (*is_compare)(const pk_Expr*);
|
||||
int (*star_level)(const pk_Expr*);
|
||||
/* emit */
|
||||
void (*emit_)(pk_Expr*, pk_CodeEmitContext*);
|
||||
bool (*emit_del)(pk_Expr*, pk_CodeEmitContext*);
|
||||
bool (*emit_store)(pk_Expr*, pk_CodeEmitContext*);
|
||||
void (*emit_inplace)(pk_Expr*, pk_CodeEmitContext*);
|
||||
bool (*emit_store_inplace)(pk_Expr*, pk_CodeEmitContext*);
|
||||
} pk_ExprVt;
|
||||
|
||||
#define COMMON_HEADER \
|
||||
pk_ExprVt* vt; \
|
||||
int line;
|
||||
|
||||
typedef struct pk_Expr{
|
||||
COMMON_HEADER
|
||||
} pk_Expr;
|
||||
|
||||
void pk_ExprVt__ctor(pk_ExprVt* vt);
|
||||
void pk_Expr__delete(pk_Expr* self);
|
||||
|
||||
void pk_Expr__initialize();
|
||||
#define pk_Expr__finalize() // do nothing
|
||||
|
||||
typedef struct pk_NameExpr{
|
||||
COMMON_HEADER
|
||||
StrName name;
|
||||
NameScope scope;
|
||||
} pk_NameExpr;
|
||||
|
||||
typedef struct pk_StarredExpr{
|
||||
COMMON_HEADER
|
||||
pk_Expr* child;
|
||||
int level;
|
||||
} pk_StarredExpr;
|
||||
|
||||
// InvertExpr, NotExpr, NegatedExpr
|
||||
// NOTE: NegatedExpr always contains a non-const child. Should not generate -1 or -0.1
|
||||
typedef struct pk_UnaryExpr{
|
||||
COMMON_HEADER
|
||||
pk_Expr* child;
|
||||
Opcode opcode;
|
||||
} pk_UnaryExpr;
|
||||
|
||||
// LongExpr, BytesExpr
|
||||
typedef struct pk_RawStringExpr{
|
||||
COMMON_HEADER
|
||||
c11_string value;
|
||||
Opcode opcode;
|
||||
} pk_RawStringExpr;
|
||||
|
||||
typedef struct pk_ImagExpr{
|
||||
COMMON_HEADER
|
||||
double value;
|
||||
} pk_ImagExpr;
|
||||
|
||||
typedef struct pk_LiteralExpr{
|
||||
COMMON_HEADER
|
||||
const TokenValue* value;
|
||||
} pk_LiteralExpr;
|
||||
|
||||
typedef struct pk_SliceExpr{
|
||||
COMMON_HEADER
|
||||
pk_Expr* start;
|
||||
pk_Expr* stop;
|
||||
pk_Expr* step;
|
||||
} pk_SliceExpr;
|
||||
|
||||
// ListExpr, DictExpr, SetExpr, TupleExpr
|
||||
typedef struct pk_SequenceExpr{
|
||||
COMMON_HEADER
|
||||
c11_array/*T=Expr* */ items;
|
||||
Opcode opcode;
|
||||
} pk_SequenceExpr;
|
||||
|
||||
typedef struct pk_CompExpr{
|
||||
COMMON_HEADER
|
||||
pk_Expr* expr; // loop expr
|
||||
pk_Expr* vars; // loop vars
|
||||
pk_Expr* iter; // loop iter
|
||||
pk_Expr* cond; // optional if condition
|
||||
|
||||
Opcode op0;
|
||||
Opcode op1;
|
||||
} pk_CompExpr;
|
||||
|
||||
typedef struct pk_LambdaExpr{
|
||||
COMMON_HEADER
|
||||
int index;
|
||||
} pk_LambdaExpr;
|
||||
|
||||
typedef struct pk_FStringExpr{
|
||||
COMMON_HEADER
|
||||
c11_string src;
|
||||
} pk_FStringExpr;
|
||||
|
||||
// AndExpr, OrExpr
|
||||
typedef struct pk_LogicBinaryExpr{
|
||||
COMMON_HEADER
|
||||
pk_Expr* lhs;
|
||||
pk_Expr* rhs;
|
||||
Opcode opcode;
|
||||
} pk_LogicBinaryExpr;
|
||||
|
||||
typedef struct pk_GroupedExpr{
|
||||
COMMON_HEADER
|
||||
pk_Expr* child;
|
||||
} pk_GroupedExpr;
|
||||
|
||||
typedef struct pk_BinaryExpr{
|
||||
COMMON_HEADER
|
||||
pk_Expr* lhs;
|
||||
pk_Expr* rhs;
|
||||
TokenIndex op;
|
||||
bool inplace;
|
||||
} pk_BinaryExpr;
|
||||
|
||||
typedef struct pk_TernaryExpr{
|
||||
COMMON_HEADER
|
||||
pk_Expr* cond;
|
||||
pk_Expr* true_expr;
|
||||
pk_Expr* false_expr;
|
||||
} pk_TernaryExpr;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,464 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/objects/codeobject.hpp"
|
||||
#include "pocketpy/compiler/lexer.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
struct CodeEmitContext;
|
||||
struct Expr;
|
||||
|
||||
typedef small_vector<Expr*, 4> Expr_vector;
|
||||
|
||||
struct Expr {
|
||||
int line = 0;
|
||||
virtual ~Expr() = default;
|
||||
virtual void emit_(CodeEmitContext* ctx) = 0;
|
||||
|
||||
Expr() = default;
|
||||
Expr(const Expr&) = delete;
|
||||
Expr(Expr&&) = delete;
|
||||
Expr& operator=(const Expr&) = delete;
|
||||
Expr& operator=(Expr&&) = delete;
|
||||
|
||||
virtual bool is_literal() const { return false; }
|
||||
virtual bool is_json_object() const { return false; }
|
||||
virtual bool is_attrib() const { return false; }
|
||||
virtual bool is_subscr() const { return false; }
|
||||
virtual bool is_compare() const { return false; }
|
||||
virtual int star_level() const { return 0; }
|
||||
virtual bool is_tuple() const { return false; }
|
||||
virtual bool is_name() const { return false; }
|
||||
bool is_starred() const { return star_level() > 0; }
|
||||
|
||||
// for OP_DELETE_XXX
|
||||
[[nodiscard]] virtual bool emit_del(CodeEmitContext* ctx) { return false; }
|
||||
// for OP_STORE_XXX
|
||||
[[nodiscard]] virtual bool emit_store(CodeEmitContext* ctx) { return false; }
|
||||
virtual void emit_inplace(CodeEmitContext* ctx) { emit_(ctx); }
|
||||
[[nodiscard]] virtual bool emit_store_inplace(CodeEmitContext* ctx) { return emit_store(ctx); }
|
||||
};
|
||||
|
||||
inline void delete_expr(Expr* p) noexcept{
|
||||
if(!p) return;
|
||||
p->~Expr();
|
||||
PoolExpr_dealloc(p);
|
||||
}
|
||||
|
||||
struct CodeEmitContext{
|
||||
VM* vm;
|
||||
FuncDecl* func; // optional, weakref
|
||||
CodeObject* co; // 1 CodeEmitContext <=> 1 CodeObject*
|
||||
vector<Expr*> _s_expr;
|
||||
int level;
|
||||
vector<StrName> global_names;
|
||||
|
||||
int curr_iblock = 0;
|
||||
bool is_compiling_class = false;
|
||||
|
||||
c11_smallmap_s2n _co_consts_string_dedup_map;
|
||||
|
||||
CodeEmitContext(VM* vm, CodeObject* co, int level) : vm(vm), co(co), level(level) {
|
||||
func = NULL;
|
||||
c11_smallmap_s2n__ctor(&_co_consts_string_dedup_map);
|
||||
}
|
||||
|
||||
int get_loop() const noexcept;
|
||||
CodeBlock* enter_block(CodeBlockType type) noexcept;
|
||||
void exit_block() noexcept;
|
||||
int emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual = false) noexcept;
|
||||
void revert_last_emit_() noexcept;
|
||||
int emit_int(i64 value, int line) noexcept;
|
||||
void patch_jump(int index) noexcept;
|
||||
bool add_label(StrName name) noexcept;
|
||||
int add_varname(StrName name) noexcept;
|
||||
int add_const(PyVar) noexcept;
|
||||
int add_const_string(std::string_view) noexcept;
|
||||
void emit_store_name(NameScope scope, StrName name, int line) noexcept;
|
||||
void try_merge_for_iter_store(int) noexcept;
|
||||
// emit top -> pop -> delete
|
||||
void s_emit_top() noexcept{
|
||||
s_debug_info("s_emit_top");
|
||||
Expr* e = _s_expr.popx_back();
|
||||
e->emit_(this);
|
||||
delete_expr(e);
|
||||
}
|
||||
// push
|
||||
void s_push(Expr* expr) noexcept{
|
||||
s_debug_info("s_push");
|
||||
_s_expr.push_back(expr);
|
||||
}
|
||||
// top
|
||||
Expr* s_top() noexcept{
|
||||
return _s_expr.back();
|
||||
}
|
||||
// size
|
||||
int s_size() const noexcept{
|
||||
return _s_expr.size();
|
||||
}
|
||||
// pop -> delete
|
||||
void s_pop() noexcept{
|
||||
s_debug_info("s_pop");
|
||||
Expr* e = _s_expr.popx_back();
|
||||
delete_expr(e);
|
||||
}
|
||||
// pop move
|
||||
Expr* s_popx() noexcept{
|
||||
s_debug_info("s_popx");
|
||||
return _s_expr.popx_back();
|
||||
}
|
||||
// clean
|
||||
void s_clean() noexcept{
|
||||
s_debug_info("s_clean");
|
||||
c11_smallmap_s2n__dtor(&_co_consts_string_dedup_map);
|
||||
for(Expr* e: _s_expr) delete_expr(e);
|
||||
_s_expr.clear();
|
||||
}
|
||||
// emit decorators
|
||||
void s_emit_decorators(int count) noexcept;
|
||||
// debug stack
|
||||
#if PK_DEBUG_COMPILER
|
||||
void s_debug_info(const char* op) noexcept{
|
||||
SStream ss;
|
||||
for(int i=0; i<s_size(); i++) {
|
||||
Expr* e = _s_expr[i];
|
||||
ss << typeid(*e).name();
|
||||
if(i != s_size() - 1) ss << ", ";
|
||||
}
|
||||
printf("[%s] %s\n", ss.str().c_str(), op);
|
||||
}
|
||||
#else
|
||||
void s_debug_info(const char*) noexcept{}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct NameExpr : Expr {
|
||||
StrName name;
|
||||
NameScope scope;
|
||||
|
||||
NameExpr(StrName name, NameScope scope) : name(name), scope(scope) {}
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
bool emit_del(CodeEmitContext* ctx) override;
|
||||
bool emit_store(CodeEmitContext* ctx) override;
|
||||
|
||||
bool is_name() const override { return true; }
|
||||
};
|
||||
|
||||
struct _UnaryExpr : Expr {
|
||||
Expr* child;
|
||||
_UnaryExpr(Expr* child) : child(child) {}
|
||||
_UnaryExpr() : child(nullptr) {}
|
||||
~_UnaryExpr() { delete_expr(child); }
|
||||
};
|
||||
|
||||
struct _BinaryExpr : Expr {
|
||||
Expr* lhs;
|
||||
Expr* rhs;
|
||||
_BinaryExpr(Expr* lhs, Expr* rhs) : lhs(lhs), rhs(rhs) {}
|
||||
_BinaryExpr() : lhs(nullptr), rhs(nullptr) {}
|
||||
~_BinaryExpr() {
|
||||
delete_expr(lhs);
|
||||
delete_expr(rhs);
|
||||
}
|
||||
};
|
||||
|
||||
struct InvertExpr : _UnaryExpr {
|
||||
using _UnaryExpr::_UnaryExpr;
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct StarredExpr : _UnaryExpr {
|
||||
int level;
|
||||
|
||||
StarredExpr(Expr* child, int level) : _UnaryExpr(child), level(level) {}
|
||||
|
||||
int star_level() const override { return level; }
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
bool emit_store(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct NotExpr : _UnaryExpr {
|
||||
using _UnaryExpr::_UnaryExpr;
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct AndExpr : _BinaryExpr {
|
||||
using _BinaryExpr::_BinaryExpr;
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct OrExpr : _BinaryExpr {
|
||||
using _BinaryExpr::_BinaryExpr;
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
// [None, True, False, ...]
|
||||
struct Literal0Expr : Expr {
|
||||
TokenIndex token;
|
||||
|
||||
Literal0Expr(TokenIndex token) : token(token) {}
|
||||
|
||||
bool is_json_object() const override { return true; }
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct LongExpr : Expr {
|
||||
Str s;
|
||||
|
||||
LongExpr(const Str& s) : s(s) {}
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct BytesExpr : Expr {
|
||||
Str s;
|
||||
|
||||
BytesExpr(const Str& s) : s(s) {}
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct ImagExpr : Expr {
|
||||
f64 value;
|
||||
|
||||
ImagExpr(f64 value) : value(value) {}
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
// @num, @str which needs to invoke OP_LOAD_CONST
|
||||
struct LiteralExpr : Expr {
|
||||
TokenValue value;
|
||||
|
||||
LiteralExpr(TokenValue value) : value(value) {}
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
|
||||
bool is_literal() const override { return true; }
|
||||
|
||||
bool is_json_object() const override { return true; }
|
||||
};
|
||||
|
||||
struct NegatedExpr : _UnaryExpr {
|
||||
using _UnaryExpr::_UnaryExpr;
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
bool is_json_object() const override { return child->is_literal(); }
|
||||
};
|
||||
|
||||
struct SliceExpr : Expr {
|
||||
Expr* start = nullptr;
|
||||
Expr* stop = nullptr;
|
||||
Expr* step = nullptr;
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
|
||||
~SliceExpr() {
|
||||
delete_expr(start);
|
||||
delete_expr(stop);
|
||||
delete_expr(step);
|
||||
}
|
||||
};
|
||||
|
||||
struct DictItemExpr : Expr {
|
||||
Expr* key; // maybe nullptr if it is **kwargs
|
||||
Expr* value;
|
||||
|
||||
DictItemExpr(): key(nullptr), value(nullptr) {}
|
||||
|
||||
int star_level() const override { return value->star_level(); }
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
|
||||
~DictItemExpr() {
|
||||
delete_expr(key);
|
||||
delete_expr(value);
|
||||
}
|
||||
};
|
||||
|
||||
struct SequenceExpr : Expr {
|
||||
array<Expr*> items;
|
||||
|
||||
SequenceExpr(int count) : items(count) {}
|
||||
|
||||
virtual Opcode opcode() const = 0;
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override {
|
||||
for(auto& item: items) item->emit_(ctx);
|
||||
ctx->emit_(opcode(), items.size(), line);
|
||||
}
|
||||
|
||||
~SequenceExpr() {
|
||||
for(Expr* item: items) delete_expr(item);
|
||||
}
|
||||
};
|
||||
|
||||
struct ListExpr : SequenceExpr {
|
||||
using SequenceExpr::SequenceExpr;
|
||||
|
||||
Opcode opcode() const override {
|
||||
for(auto& e: items)
|
||||
if(e->is_starred()) return OP_BUILD_LIST_UNPACK;
|
||||
return OP_BUILD_LIST;
|
||||
}
|
||||
|
||||
bool is_json_object() const override { return true; }
|
||||
};
|
||||
|
||||
struct DictExpr : SequenceExpr {
|
||||
using SequenceExpr::SequenceExpr;
|
||||
|
||||
Opcode opcode() const override {
|
||||
for(auto& e: items)
|
||||
if(e->is_starred()) return OP_BUILD_DICT_UNPACK;
|
||||
return OP_BUILD_DICT;
|
||||
}
|
||||
|
||||
bool is_json_object() const override { return true; }
|
||||
};
|
||||
|
||||
struct SetExpr : SequenceExpr {
|
||||
using SequenceExpr::SequenceExpr;
|
||||
|
||||
Opcode opcode() const override {
|
||||
for(auto& e: items)
|
||||
if(e->is_starred()) return OP_BUILD_SET_UNPACK;
|
||||
return OP_BUILD_SET;
|
||||
}
|
||||
};
|
||||
|
||||
struct TupleExpr : SequenceExpr {
|
||||
using SequenceExpr::SequenceExpr;
|
||||
|
||||
bool is_tuple() const override { return true; }
|
||||
|
||||
Opcode opcode() const override {
|
||||
for(auto& e: items)
|
||||
if(e->is_starred()) return OP_BUILD_TUPLE_UNPACK;
|
||||
return OP_BUILD_TUPLE;
|
||||
}
|
||||
|
||||
bool emit_store(CodeEmitContext* ctx) override;
|
||||
bool emit_del(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct CompExpr : Expr {
|
||||
Expr* expr = nullptr; // loop expr
|
||||
Expr* vars = nullptr; // loop vars
|
||||
Expr* iter = nullptr; // loop iter
|
||||
Expr* cond = nullptr; // optional if condition
|
||||
|
||||
Opcode op0;
|
||||
Opcode op1;
|
||||
|
||||
CompExpr(Opcode op0, Opcode op1) : op0(op0), op1(op1) {}
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
|
||||
~CompExpr() {
|
||||
delete_expr(expr);
|
||||
delete_expr(vars);
|
||||
delete_expr(iter);
|
||||
delete_expr(cond);
|
||||
}
|
||||
};
|
||||
|
||||
struct LambdaExpr : Expr {
|
||||
int index;
|
||||
|
||||
LambdaExpr(int index) : index(index) {}
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override {
|
||||
ctx->emit_(OP_LOAD_FUNCTION, index, line);
|
||||
}
|
||||
};
|
||||
|
||||
struct FStringExpr : Expr {
|
||||
Str src;
|
||||
|
||||
FStringExpr(const Str& src) : src(src) {}
|
||||
|
||||
void _load_simple_expr(CodeEmitContext* ctx, Str expr);
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct SubscrExpr : _BinaryExpr {
|
||||
using _BinaryExpr::_BinaryExpr;
|
||||
bool is_subscr() const override { return true; }
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
bool emit_del(CodeEmitContext* ctx) override;
|
||||
bool emit_store(CodeEmitContext* ctx) override;
|
||||
|
||||
void emit_inplace(CodeEmitContext* ctx) override;
|
||||
bool emit_store_inplace(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct AttribExpr : _UnaryExpr {
|
||||
StrName name;
|
||||
|
||||
AttribExpr(Expr* child, StrName name) : _UnaryExpr(child), name(name) {}
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
bool emit_del(CodeEmitContext* ctx) override;
|
||||
bool emit_store(CodeEmitContext* ctx) override;
|
||||
void emit_method(CodeEmitContext* ctx);
|
||||
|
||||
bool is_attrib() const override { return true; }
|
||||
|
||||
void emit_inplace(CodeEmitContext* ctx) override;
|
||||
bool emit_store_inplace(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct CallExpr : Expr {
|
||||
Expr* callable;
|
||||
Expr_vector args;
|
||||
// **a will be interpreted as a special keyword argument: {"**": a}
|
||||
vector<pair<StrName, Expr*>> kwargs;
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
|
||||
~CallExpr() {
|
||||
delete_expr(callable);
|
||||
for(Expr* arg: args) delete_expr(arg);
|
||||
for(auto [_, arg]: kwargs) delete_expr(arg);
|
||||
}
|
||||
};
|
||||
|
||||
struct GroupedExpr : _UnaryExpr {
|
||||
using _UnaryExpr::_UnaryExpr;
|
||||
void emit_(CodeEmitContext* ctx) override { child->emit_(ctx); }
|
||||
|
||||
bool emit_del(CodeEmitContext* ctx) override { return child->emit_del(ctx); }
|
||||
|
||||
bool emit_store(CodeEmitContext* ctx) override { return child->emit_store(ctx); }
|
||||
};
|
||||
|
||||
struct BinaryExpr : _BinaryExpr {
|
||||
TokenIndex op;
|
||||
bool inplace;
|
||||
|
||||
BinaryExpr(TokenIndex op, bool inplace = false)
|
||||
: _BinaryExpr(), op(op), inplace(inplace) {}
|
||||
|
||||
bool is_compare() const override;
|
||||
void _emit_compare(CodeEmitContext*, small_vector_2<int, 8>&);
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct TernaryExpr : Expr {
|
||||
Expr* cond = nullptr;
|
||||
Expr* true_expr = nullptr;
|
||||
Expr* false_expr = nullptr;
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
|
||||
~TernaryExpr() {
|
||||
delete_expr(cond);
|
||||
delete_expr(true_expr);
|
||||
delete_expr(false_expr);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace pkpy
|
@ -103,6 +103,8 @@ Error* pk_Lexer__process(pk_SourceData_ src, pk_TokenArray* out_tokens);
|
||||
Error* pk_Lexer__process_and_dump(pk_SourceData_ src, py_Str* out_string);
|
||||
void pk_TokenArray__dtor(pk_TokenArray* self);
|
||||
|
||||
#define Token__sv(self) (c11_string){(self)->start, (self)->length}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -11,14 +11,14 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
PyVar* FastLocals__try_get_by_name(PyVar* locals, const CodeObject* co, py_Name name);
|
||||
pk_NameDict* FastLocals__to_namedict(PyVar* locals, const CodeObject* co);
|
||||
py_TValue* FastLocals__try_get_by_name(py_TValue* locals, const CodeObject* co, py_Name name);
|
||||
pk_NameDict* FastLocals__to_namedict(py_TValue* locals, const CodeObject* co);
|
||||
|
||||
typedef struct ValueStack {
|
||||
// We allocate extra PK_VM_STACK_SIZE/128 places to keep `_sp` valid when `is_overflow() == true`.
|
||||
PyVar* sp;
|
||||
PyVar* end;
|
||||
PyVar begin[PK_VM_STACK_SIZE + PK_VM_STACK_SIZE / 128];
|
||||
py_TValue* sp;
|
||||
py_TValue* end;
|
||||
py_TValue begin[PK_VM_STACK_SIZE + PK_VM_STACK_SIZE / 128];
|
||||
} ValueStack;
|
||||
|
||||
void ValueStack__ctor(ValueStack* self);
|
||||
@ -39,14 +39,14 @@ typedef struct Frame {
|
||||
const CodeObject* co;
|
||||
PyObject* module;
|
||||
PyObject* function; // a function object or NULL (global scope)
|
||||
PyVar* p0; // unwinding base
|
||||
PyVar* locals; // locals base
|
||||
py_TValue* p0; // unwinding base
|
||||
py_TValue* locals; // locals base
|
||||
const CodeObject* locals_co;
|
||||
UnwindTarget* uw_list;
|
||||
} Frame;
|
||||
|
||||
|
||||
Frame* Frame__new(const CodeObject* co, const PyVar* module, const PyVar* function, PyVar* p0, PyVar* locals, const CodeObject* locals_co);
|
||||
Frame* Frame__new(const CodeObject* co, const py_TValue* module, const py_TValue* function, py_TValue* p0, py_TValue* locals, const CodeObject* locals_co);
|
||||
void Frame__delete(Frame* self);
|
||||
|
||||
PK_INLINE int Frame__ip(const Frame* self){
|
||||
@ -67,11 +67,15 @@ PK_INLINE pk_NameDict* Frame__f_globals(Frame* self){
|
||||
return PyObject__dict(self->module);
|
||||
}
|
||||
|
||||
PK_INLINE PyVar* Frame__f_globals_try_get(Frame* self, py_Name name){
|
||||
PK_INLINE py_TValue* Frame__f_globals_try_get(Frame* self, py_Name name){
|
||||
return pk_NameDict__try_get(Frame__f_globals(self), name);
|
||||
}
|
||||
|
||||
PyVar* Frame__f_closure_try_get(Frame* self, py_Name name);
|
||||
PK_INLINE py_TValue* Frame__f_locals_try_get(Frame* self, py_Name name){
|
||||
return FastLocals__try_get_by_name(self->locals, self->locals_co, name);
|
||||
}
|
||||
|
||||
py_TValue* Frame__f_closure_try_get(Frame* self, py_Name name);
|
||||
|
||||
int Frame__prepare_jump_exception_handler(Frame* self, ValueStack*);
|
||||
void Frame__prepare_jump_break(Frame* self, ValueStack*, int);
|
||||
@ -80,23 +84,8 @@ int Frame__exit_block(Frame* self, ValueStack*, int);
|
||||
|
||||
void Frame__gc_mark(Frame* self);
|
||||
UnwindTarget* Frame__find_unwind_target(Frame* self, int iblock);
|
||||
void Frame__set_unwind_target(Frame* self, PyVar* sp);
|
||||
void Frame__set_unwind_target(Frame* self, py_TValue* sp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// some patch here
|
||||
#ifdef __cplusplus
|
||||
#include "pocketpy/objects/codeobject.hpp"
|
||||
|
||||
extern "C"{
|
||||
inline PyVar* Frame__f_closure_try_get(Frame* self, StrName name){
|
||||
if(self->function == NULL) return NULL;
|
||||
pkpy::Function* fn = PyObject__as(pkpy::Function, self->function);
|
||||
if(fn->_closure == nullptr) return nullptr;
|
||||
return pk_NameDict__try_get(fn->_closure, name);
|
||||
}
|
||||
}
|
||||
#endif
|
@ -12,8 +12,8 @@ typedef struct pk_TypeInfo{
|
||||
py_Name name;
|
||||
py_Type base;
|
||||
|
||||
PyVar self; // the type object itself
|
||||
PyVar module; // the module where the type is defined
|
||||
py_TValue self; // the type object itself
|
||||
py_TValue module; // the module where the type is defined
|
||||
bool subclass_enabled;
|
||||
|
||||
void (*dtor)(void*);
|
||||
@ -38,7 +38,7 @@ typedef struct pk_TypeInfo{
|
||||
py_CFunction on_end_subclass; // for enum module
|
||||
} pk_TypeInfo;
|
||||
|
||||
void pk_TypeInfo__ctor(pk_TypeInfo* self, py_Name name, py_Type base, PyObject* obj, const PyVar* module, bool subclass_enabled);
|
||||
void pk_TypeInfo__ctor(pk_TypeInfo* self, py_Name name, py_Type base, PyObject* obj, const py_TValue* module, bool subclass_enabled);
|
||||
void pk_TypeInfo__dtor(pk_TypeInfo* self);
|
||||
|
||||
typedef struct pk_VM {
|
||||
@ -47,24 +47,26 @@ typedef struct pk_VM {
|
||||
pk_NameDict modules;
|
||||
c11_vector/*T=pk_TypeInfo*/ types;
|
||||
|
||||
PyVar StopIteration; // a special Exception class
|
||||
PyVar builtins; // builtins module
|
||||
PyVar main; // __main__ module
|
||||
py_TValue StopIteration; // a special Exception class
|
||||
py_TValue builtins; // builtins module
|
||||
py_TValue main; // __main__ module
|
||||
|
||||
void (*_ceval_on_step)(Frame*, Bytecode);
|
||||
unsigned char* (*_import_file)(const char*);
|
||||
void (*_stdout)(const char*);
|
||||
void (*_stderr)(const char*);
|
||||
void (*_stdout)(const char*, ...);
|
||||
void (*_stderr)(const char*, ...);
|
||||
|
||||
// singleton objects
|
||||
PyVar True, False, None, NotImplemented, Ellipsis;
|
||||
// last error
|
||||
py_TValue True, False, None, NotImplemented, Ellipsis;
|
||||
|
||||
py_Error* last_error;
|
||||
py_TValue last_retval;
|
||||
py_TValue reg[8]; // users' registers
|
||||
|
||||
PyObject* __curr_class;
|
||||
PyObject* __cached_object_new;
|
||||
FuncDecl_ __dynamic_func_decl;
|
||||
PyVar __vectorcall_buffer[PK_MAX_CO_VARNAMES];
|
||||
py_TValue __vectorcall_buffer[PK_MAX_CO_VARNAMES];
|
||||
|
||||
pk_ManagedHeap heap;
|
||||
ValueStack stack; // put `stack` at the end for better cache locality
|
||||
@ -87,7 +89,7 @@ typedef enum pk_FrameResult{
|
||||
|
||||
pk_FrameResult pk_VM__run_top_frame(pk_VM* self);
|
||||
|
||||
py_Type pk_VM__new_type(pk_VM* self, const char* name, py_Type base, const PyVar* module, bool subclass_enabled);
|
||||
py_Type pk_VM__new_type(pk_VM* self, const char* name, py_Type base, const py_TValue* module, bool subclass_enabled);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -14,8 +14,9 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
typedef int16_t py_Type;
|
||||
typedef struct PyObject PyObject;
|
||||
|
||||
typedef struct PyVar{
|
||||
typedef struct py_TValue{
|
||||
py_Type type;
|
||||
bool is_ptr;
|
||||
int extra;
|
||||
@ -26,9 +27,9 @@ typedef struct PyVar{
|
||||
void* _ptr;
|
||||
// Vec2
|
||||
};
|
||||
} PyVar;
|
||||
} py_TValue;
|
||||
|
||||
static_assert(sizeof(PyVar) <= 16, "!sizeof(PyVar) <= 16");
|
||||
static_assert(sizeof(py_TValue) <= 16, "!sizeof(py_TValue) <= 16");
|
||||
|
||||
/* predefined vars */
|
||||
static const py_Type tp_object = {1}, tp_type = {2};
|
||||
@ -44,7 +45,7 @@ static const py_Type tp_ellipsis = {26};
|
||||
static const py_Type tp_op_call = {27}, tp_op_yield = {28};
|
||||
static const py_Type tp_syntax_error = {29}, tp_stop_iteration = {30};
|
||||
|
||||
extern PyVar PY_NULL, PY_OP_CALL, PY_OP_YIELD;
|
||||
extern py_TValue PY_NULL, PY_OP_CALL, PY_OP_YIELD;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ typedef struct CodeObject {
|
||||
c11_vector/*T=Bytecode*/ codes;
|
||||
c11_vector/*T=CodeObjectByteCodeEx*/ codes_ex;
|
||||
|
||||
c11_vector/*T=PyVar*/ consts; // constants
|
||||
c11_vector/*T=py_TValue*/ consts; // constants
|
||||
c11_vector/*T=StrName*/ varnames; // local variables
|
||||
int nlocals; // cached varnames.size()
|
||||
|
||||
@ -95,7 +95,7 @@ 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
|
||||
py_TValue value; // default value
|
||||
} FuncDeclKwArg;
|
||||
|
||||
typedef struct FuncDecl {
|
||||
@ -119,7 +119,7 @@ typedef FuncDecl* FuncDecl_;
|
||||
|
||||
FuncDecl_ FuncDecl__rcnew(pk_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__add_kwarg(FuncDecl* self, int index, uint16_t key, const py_TValue* value);
|
||||
void FuncDecl__gc_mark(const FuncDecl* self);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -49,7 +49,7 @@ pkpy_Dict pkpy_Dict__copy(const pkpy_Dict* self);
|
||||
* @param val value to set
|
||||
* @return `true` if the key is newly added, `false` if the key already exists
|
||||
*/
|
||||
bool pkpy_Dict__set(pkpy_Dict* self, PyVar key, PyVar val);
|
||||
bool pkpy_Dict__set(pkpy_Dict* self, py_TValue key, py_TValue val);
|
||||
|
||||
/**
|
||||
* @brief Check if a key exists in the `pkpy_Dict`
|
||||
@ -58,7 +58,7 @@ bool pkpy_Dict__set(pkpy_Dict* self, PyVar key, PyVar val);
|
||||
* @param key key to check
|
||||
* @return `true` if the key exists, `false` otherwise
|
||||
*/
|
||||
bool pkpy_Dict__contains(const pkpy_Dict* self, PyVar key);
|
||||
bool pkpy_Dict__contains(const pkpy_Dict* self, py_TValue key);
|
||||
|
||||
/**
|
||||
* @brief Remove a key from the `pkpy_Dict`
|
||||
@ -67,7 +67,7 @@ bool pkpy_Dict__contains(const pkpy_Dict* self, PyVar key);
|
||||
* @param key key to remove
|
||||
* @return `true` if the key was found and removed, `false` if the key doesn't exist
|
||||
*/
|
||||
bool pkpy_Dict__del(pkpy_Dict* self, PyVar key);
|
||||
bool pkpy_Dict__del(pkpy_Dict* self, py_TValue key);
|
||||
|
||||
/**
|
||||
* @brief Try to get a value from the `pkpy_Dict`
|
||||
@ -76,7 +76,7 @@ bool pkpy_Dict__del(pkpy_Dict* self, PyVar key);
|
||||
* @param key key to get
|
||||
* @return the value associated with the key, `NULL` if the key doesn't exist
|
||||
*/
|
||||
const PyVar* pkpy_Dict__try_get(const pkpy_Dict* self, PyVar key);
|
||||
const py_TValue* pkpy_Dict__try_get(const pkpy_Dict* self, py_TValue key);
|
||||
|
||||
/**
|
||||
* @brief Update the `pkpy_Dict` with another one
|
||||
@ -106,7 +106,7 @@ pkpy_DictIter pkpy_Dict__iter(const pkpy_Dict* self);
|
||||
* @param value value will be filled with the current value, can be `NULL` if not needed
|
||||
* @return `true` if the iteration is still valid, `false` otherwise
|
||||
*/
|
||||
bool pkpy_DictIter__next(pkpy_DictIter* self, PyVar* key, PyVar* value);
|
||||
bool pkpy_DictIter__next(pkpy_DictIter* self, py_TValue* key, py_TValue* value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ extern "C" {
|
||||
|
||||
#define SMALLMAP_T__HEADER
|
||||
#define K uint16_t
|
||||
#define V PyVar
|
||||
#define V py_TValue
|
||||
#define NAME pk_NameDict
|
||||
#include "pocketpy/xmacros/smallmap.h"
|
||||
#undef SMALLMAP_T__HEADER
|
||||
|
@ -22,18 +22,18 @@ typedef struct PyObject{
|
||||
|
||||
static_assert(sizeof(PyObject) <= 8, "!(sizeof(PyObject) <= 8)");
|
||||
|
||||
PyVar* PyObject__slots(PyObject* self);
|
||||
py_TValue* PyObject__slots(PyObject* self);
|
||||
pk_NameDict* PyObject__dict(PyObject* self);
|
||||
void* PyObject__value(PyObject* self);
|
||||
|
||||
#define PK_OBJ_HEADER_SIZE(slots) ((slots)>=0 ? 8+sizeof(PyVar)*(slots) : 8+sizeof(pk_NameDict))
|
||||
#define PK_OBJ_HEADER_SIZE(slots) ((slots)>=0 ? 8+sizeof(py_TValue)*(slots) : 8+sizeof(pk_NameDict))
|
||||
|
||||
PyObject* PyObject__new(py_Type type, int slots, int size);
|
||||
void PyObject__delete(PyObject* self);
|
||||
|
||||
PK_INLINE PyVar PyVar__fromobj(PyObject* obj){
|
||||
PK_INLINE py_TValue PyVar__fromobj(PyObject* obj){
|
||||
if(!obj) return PY_NULL;
|
||||
PyVar retval = {
|
||||
py_TValue retval = {
|
||||
.type = obj->type,
|
||||
.is_ptr = true,
|
||||
._obj = obj
|
||||
|
@ -4,15 +4,15 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
/************* Public Types *************/
|
||||
typedef struct PyObject PyObject;
|
||||
typedef struct PyVar PyVar;
|
||||
typedef struct py_TValue py_TValue;
|
||||
typedef struct pk_VM pk_VM;
|
||||
typedef uint16_t py_Name;
|
||||
typedef int16_t py_Type;
|
||||
typedef PyVar* py_Ref;
|
||||
typedef py_TValue* py_Ref;
|
||||
typedef struct py_Str py_Str;
|
||||
typedef int (*py_CFunction)(int argc, py_Ref argv);
|
||||
|
||||
typedef struct py_Error{
|
||||
typedef struct py_Error {
|
||||
py_Type type;
|
||||
} py_Error;
|
||||
|
||||
@ -30,8 +30,8 @@ void py_finalize();
|
||||
|
||||
/// Run a simple source string. Do not change the stack.
|
||||
int py_exec(const char*);
|
||||
/// Eval a simple expression. If succeed, the result will be pushed onto the stack.
|
||||
int py_eval(const char*);
|
||||
/// Eval a simple expression. The result is pushed to the stack.
|
||||
int py_eval(const char*, py_Ref out);
|
||||
|
||||
/************* Values Creation *************/
|
||||
void py_newint(py_Ref, int64_t);
|
||||
@ -49,10 +49,20 @@ void py_newtuple(py_Ref, int);
|
||||
|
||||
// new style decl-based function
|
||||
void py_newfunction(py_Ref out, py_CFunction, const char* sig);
|
||||
void py_newfunction2(py_Ref out, py_CFunction, const char* sig, BindType bt, const char* docstring, const py_Ref upvalue);
|
||||
void py_newfunction2(py_Ref out,
|
||||
py_CFunction,
|
||||
const char* sig,
|
||||
BindType bt,
|
||||
const char* docstring,
|
||||
const py_Ref upvalue);
|
||||
// old style argc-based function
|
||||
void py_newnativefunc(py_Ref out, py_CFunction, int argc);
|
||||
void py_newnativefunc2(py_Ref out, py_CFunction, int argc, BindType bt, const char* docstring, const py_Ref upvalue);
|
||||
void py_newnativefunc2(py_Ref out,
|
||||
py_CFunction,
|
||||
int argc,
|
||||
BindType bt,
|
||||
const char* docstring,
|
||||
const py_Ref upvalue);
|
||||
|
||||
/// Create a new object.
|
||||
/// @param out output reference.
|
||||
@ -91,6 +101,9 @@ bool py_istype(const py_Ref, py_Type);
|
||||
// bool py_issubclass(py_Type derived, py_Type base);
|
||||
|
||||
/************* References *************/
|
||||
py_Ref py_getreg(int i);
|
||||
void py_setreg(int i, const py_Ref val);
|
||||
|
||||
py_Ref py_getdict(const py_Ref self, py_Name name);
|
||||
void py_setdict(py_Ref self, py_Name name, const py_Ref val);
|
||||
|
||||
@ -146,6 +159,13 @@ int py_eq(const py_Ref, const py_Ref);
|
||||
int py_le(const py_Ref, const py_Ref);
|
||||
int py_hash(const py_Ref, int64_t* out);
|
||||
|
||||
int py_str(const py_Ref);
|
||||
int py_repr(const py_Ref);
|
||||
|
||||
int py_vectorcall(int argc, int kwargc);
|
||||
int py_call(py_Ref f, ...);
|
||||
int py_callmethod(py_Ref self, py_Name name, ...);
|
||||
|
||||
#define py_isnull(self) ((self)->type == 0)
|
||||
|
||||
/* tuple */
|
||||
@ -154,14 +174,12 @@ int py_hash(const py_Ref, int64_t* out);
|
||||
py_Ref py_tuple__getitem(const py_Ref self, int i);
|
||||
void py_tuple__setitem(py_Ref self, int i, const py_Ref val);
|
||||
int py_tuple__len(const py_Ref self);
|
||||
bool py_tuple__contains(const py_Ref self, const py_Ref val);
|
||||
|
||||
// unchecked functions, if self is not a list, the behavior is undefined
|
||||
py_Ref py_list__getitem(const py_Ref self, int i);
|
||||
void py_list__setitem(py_Ref self, int i, const py_Ref val);
|
||||
void py_list__delitem(py_Ref self, int i);
|
||||
int py_list__len(const py_Ref self);
|
||||
bool py_list__contains(const py_Ref self, const py_Ref val);
|
||||
void py_list__append(py_Ref self, const py_Ref val);
|
||||
void py_list__extend(py_Ref self, const py_Ref begin, const py_Ref end);
|
||||
void py_list__clear(py_Ref self);
|
||||
@ -175,9 +193,6 @@ void py_dict__setitem(py_Ref self, const py_Ref key, const py_Ref val);
|
||||
void py_dict__delitem(py_Ref self, const py_Ref key);
|
||||
void py_dict__clear(py_Ref self);
|
||||
|
||||
int py_str(const py_Ref, char* out);
|
||||
int py_repr(const py_Ref, char* out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -30,7 +30,6 @@ OPCODE(LOAD_CLASS_GLOBAL)
|
||||
OPCODE(LOAD_METHOD)
|
||||
OPCODE(LOAD_SUBSCR)
|
||||
OPCODE(LOAD_SUBSCR_FAST)
|
||||
OPCODE(LOAD_SUBSCR_SMALL_INT)
|
||||
|
||||
OPCODE(STORE_FAST)
|
||||
OPCODE(STORE_NAME)
|
||||
@ -86,7 +85,8 @@ OPCODE(BINARY_MATMUL)
|
||||
|
||||
OPCODE(IS_OP)
|
||||
OPCODE(IS_NOT_OP)
|
||||
OPCODE(CONTAINS_OP)
|
||||
OPCODE(IN_OP)
|
||||
OPCODE(NOT_IN_OP)
|
||||
/**************************/
|
||||
OPCODE(JUMP_FORWARD)
|
||||
OPCODE(POP_JUMP_IF_FALSE)
|
||||
|
@ -243,7 +243,7 @@ PK_THREAD_LOCAL FixedMemoryPool PoolFrame;
|
||||
PK_THREAD_LOCAL MemoryPool PoolObject;
|
||||
PK_THREAD_LOCAL bool _Pools_initialized = false;
|
||||
|
||||
void Pools_initialize(){
|
||||
void pk_MemoryPools__initialize(){
|
||||
if(_Pools_initialized) return;
|
||||
FixedMemoryPool__ctor(&PoolExpr, kPoolExprBlockSize, 64);
|
||||
FixedMemoryPool__ctor(&PoolFrame, kPoolFrameBlockSize, 128);
|
||||
@ -251,7 +251,7 @@ void Pools_initialize(){
|
||||
_Pools_initialized = true;
|
||||
}
|
||||
|
||||
void Pools_finalize(){
|
||||
void pk_MemoryPools__finalize(){
|
||||
if(!_Pools_initialized) return;
|
||||
FixedMemoryPool__dtor(&PoolExpr);
|
||||
FixedMemoryPool__dtor(&PoolFrame);
|
||||
|
@ -79,6 +79,10 @@ void pk_StrName__initialize(){
|
||||
|
||||
void pk_StrName__finalize(){
|
||||
if(!_initialized) return;
|
||||
// free all char*
|
||||
for(int i=0; i<_r_interned.count; i++){
|
||||
free(c11__getitem(char*, &_r_interned, i));
|
||||
}
|
||||
c11_smallmap_s2n__dtor(&_interned);
|
||||
c11_vector__dtor(&_r_interned);
|
||||
}
|
||||
@ -116,6 +120,11 @@ const char* pk_StrName__rmap(uint16_t index){
|
||||
return c11__getitem(char*, &_r_interned, index - 1);
|
||||
}
|
||||
|
||||
c11_string pk_StrName__rmap2(uint16_t index){
|
||||
const char* p = pk_StrName__rmap(index);
|
||||
return (c11_string){p, strlen(p)};
|
||||
}
|
||||
|
||||
|
||||
|
||||
// unary operators
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,58 +0,0 @@
|
||||
#include "pocketpy/compiler/context.h"
|
||||
#include "pocketpy/compiler/expr.h"
|
||||
|
||||
void pk_CodeEmitContext__ctor(pk_CodeEmitContext* self, CodeObject* co, FuncDecl* func, int level){
|
||||
self->co = co;
|
||||
self->func = func;
|
||||
self->level = level;
|
||||
self->curr_iblock = 0;
|
||||
self->is_compiling_class = false;
|
||||
c11_vector__ctor(&self->s_expr, sizeof(pk_Expr*));
|
||||
c11_vector__ctor(&self->global_names, sizeof(StrName));
|
||||
c11_smallmap_s2n__ctor(&self->co_consts_string_dedup_map);
|
||||
}
|
||||
|
||||
void pk_CodeEmitContext__dtor(pk_CodeEmitContext* self){
|
||||
c11_vector__dtor(&self->s_expr);
|
||||
c11_vector__dtor(&self->global_names);
|
||||
c11_smallmap_s2n__dtor(&self->co_consts_string_dedup_map);
|
||||
}
|
||||
|
||||
// emit top -> pop -> delete
|
||||
void pk_CodeEmitContext__s_emit_top(pk_CodeEmitContext* self) {
|
||||
pk_Expr* top = c11_vector__back(pk_Expr*, &self->s_expr);
|
||||
top->vt->emit_(top, self);
|
||||
c11_vector__pop(&self->s_expr);
|
||||
pk_Expr__delete(top);
|
||||
}
|
||||
// push
|
||||
void pk_CodeEmitContext__s_push(pk_CodeEmitContext* self, pk_Expr* expr) {
|
||||
c11_vector__push(pk_Expr*, &self->s_expr, expr);
|
||||
}
|
||||
// top
|
||||
pk_Expr* pk_CodeEmitContext__s_top(pk_CodeEmitContext* self){
|
||||
return c11_vector__back(pk_Expr*, &self->s_expr);
|
||||
}
|
||||
// size
|
||||
int pk_CodeEmitContext__s_size(pk_CodeEmitContext* self) {
|
||||
return self->s_expr.count;
|
||||
}
|
||||
// pop -> delete
|
||||
void pk_CodeEmitContext__s_pop(pk_CodeEmitContext* self){
|
||||
pk_Expr__delete(c11_vector__back(pk_Expr*, &self->s_expr));
|
||||
c11_vector__pop(&self->s_expr);
|
||||
}
|
||||
// pop move
|
||||
pk_Expr* pk_CodeEmitContext__s_popx(pk_CodeEmitContext* self){
|
||||
pk_Expr* e = c11_vector__back(pk_Expr*, &self->s_expr);
|
||||
c11_vector__pop(&self->s_expr);
|
||||
return e;
|
||||
}
|
||||
// clean
|
||||
void pk_CodeEmitContext__s_clean(pk_CodeEmitContext* self){
|
||||
c11_smallmap_s2n__dtor(&self->co_consts_string_dedup_map); // ??
|
||||
for(int i=0; i<self->s_expr.count; i++){
|
||||
pk_Expr__delete(c11__getitem(pk_Expr*, &self->s_expr, i));
|
||||
}
|
||||
c11_vector__clear(&self->s_expr);
|
||||
}
|
@ -1,837 +0,0 @@
|
||||
#include "pocketpy/compiler/expr.h"
|
||||
#include "pocketpy/compiler/context.h"
|
||||
#include "pocketpy/common/memorypool.h"
|
||||
#include "pocketpy/common/strname.h"
|
||||
#include <ctype.h>
|
||||
|
||||
static bool default_false(const pk_Expr* e) { return false; }
|
||||
static int default_zero(const pk_Expr* e) { return 0; }
|
||||
static void default_dtor(pk_Expr* e) {}
|
||||
|
||||
static bool default_emit_del(pk_Expr* e, pk_CodeEmitContext* ctx) { return false; }
|
||||
static bool default_emit_store(pk_Expr* e, pk_CodeEmitContext* ctx) { return false; }
|
||||
static void default_emit_inplace(pk_Expr* e, pk_CodeEmitContext* ctx) { e->vt->emit_(e, ctx); }
|
||||
static bool default_emit_store_inplace(pk_Expr* e, pk_CodeEmitContext* ctx) { return e->vt->emit_store(e, ctx); }
|
||||
|
||||
void pk_ExprVt__ctor(pk_ExprVt* vt){
|
||||
vt->dtor = default_dtor;
|
||||
vt->star_level = default_zero;
|
||||
vt->is_compare = default_false;
|
||||
vt->emit_ = NULL; // must be set
|
||||
vt->emit_del = default_emit_del;
|
||||
vt->emit_store = default_emit_store;
|
||||
vt->emit_inplace = default_emit_inplace;
|
||||
vt->emit_store_inplace = default_emit_store_inplace;
|
||||
}
|
||||
|
||||
void pk_Expr__delete(pk_Expr* self){
|
||||
if(!self) return;
|
||||
self->vt->dtor(self);
|
||||
PoolExpr_dealloc(self);
|
||||
}
|
||||
|
||||
/* Implementations */
|
||||
#define static_assert_expr_size(T) static_assert(sizeof(T) <= kPoolExprBlockSize, "size is too large")
|
||||
|
||||
static pk_ExprVt NameExprVt;
|
||||
|
||||
void pk_NameExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_NameExpr* self = (pk_NameExpr*)self_;
|
||||
int index = c11_smallmap_n2i__get(&ctx->co->varnames_inv, self->name, -1);
|
||||
if(self->scope == NAME_LOCAL && index >= 0) {
|
||||
pk_CodeEmitContext__emit_(ctx, OP_LOAD_FAST, index, self->line);
|
||||
} else {
|
||||
Opcode op = ctx->level <= 1 ? OP_LOAD_GLOBAL : OP_LOAD_NONLOCAL;
|
||||
if(ctx->is_compiling_class && self->scope == NAME_GLOBAL) {
|
||||
// if we are compiling a class, we should use OP_LOAD_ATTR_GLOBAL instead of OP_LOAD_GLOBAL
|
||||
// this supports @property.setter
|
||||
op = OP_LOAD_CLASS_GLOBAL;
|
||||
// exec()/eval() won't work with OP_LOAD_ATTR_GLOBAL in class body
|
||||
} else {
|
||||
// we cannot determine the scope when calling exec()/eval()
|
||||
if(self->scope == NAME_GLOBAL_UNKNOWN) op = OP_LOAD_NAME;
|
||||
}
|
||||
pk_CodeEmitContext__emit_(ctx, op, self->name, self->line);
|
||||
}
|
||||
}
|
||||
|
||||
bool pk_NameExpr__emit_del(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_NameExpr* self = (pk_NameExpr*)self_;
|
||||
switch(self->scope) {
|
||||
case NAME_LOCAL:
|
||||
pk_CodeEmitContext__emit_(
|
||||
ctx, OP_DELETE_FAST,
|
||||
pk_CodeEmitContext__add_varname(ctx, self->name),
|
||||
self->line
|
||||
);
|
||||
break;
|
||||
case NAME_GLOBAL:
|
||||
pk_CodeEmitContext__emit_(ctx, OP_DELETE_GLOBAL, self->name, self->line);
|
||||
break;
|
||||
case NAME_GLOBAL_UNKNOWN:
|
||||
pk_CodeEmitContext__emit_(ctx, OP_DELETE_NAME, self->name, self->line);
|
||||
break;
|
||||
default: PK_UNREACHABLE();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pk_NameExpr__emit_store(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_NameExpr* self = (pk_NameExpr*)self_;
|
||||
if(ctx->is_compiling_class) {
|
||||
pk_CodeEmitContext__emit_(ctx, OP_STORE_CLASS_ATTR, self->name, self->line);
|
||||
return true;
|
||||
}
|
||||
pk_CodeEmitContext__emit_store_name(ctx, self->scope, self->name, self->line);
|
||||
return true;
|
||||
}
|
||||
|
||||
pk_NameExpr* pk_NameExpr__new(StrName name, NameScope scope){
|
||||
static_assert_expr_size(pk_NameExpr);
|
||||
pk_NameExpr* self = PoolExpr_alloc();
|
||||
self->vt = &NameExprVt;
|
||||
self->line = -1;
|
||||
self->name = name;
|
||||
self->scope = scope;
|
||||
return self;
|
||||
}
|
||||
|
||||
static pk_ExprVt StarredExprVt;
|
||||
|
||||
int pk_ExprVt__star_level(const pk_Expr* self) {
|
||||
return ((pk_StarredExpr*)self)->level;
|
||||
}
|
||||
|
||||
void pk_StarredExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_StarredExpr* self = (pk_StarredExpr*)self_;
|
||||
self->child->vt->emit_(self->child, ctx);
|
||||
pk_CodeEmitContext__emit_(ctx, OP_UNARY_STAR, self->level, self->line);
|
||||
}
|
||||
|
||||
bool pk_StarredExpr__emit_store(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_StarredExpr* self = (pk_StarredExpr*)self_;
|
||||
if(self->level != 1) return false;
|
||||
// simply proxy to child
|
||||
return self->child->vt->emit_store(self->child, ctx);
|
||||
}
|
||||
|
||||
pk_StarredExpr* pk_StarredExpr__new(pk_Expr* child, int level){
|
||||
static_assert_expr_size(pk_StarredExpr);
|
||||
pk_StarredExpr* self = PoolExpr_alloc();
|
||||
self->vt = &StarredExprVt;
|
||||
self->line = -1;
|
||||
self->child = child;
|
||||
self->level = level;
|
||||
return self;
|
||||
}
|
||||
|
||||
static pk_ExprVt UnaryExprVt;
|
||||
|
||||
void pk_UnaryExpr__dtor(pk_Expr* self_){
|
||||
pk_UnaryExpr* self = (pk_UnaryExpr*)self_;
|
||||
pk_Expr__delete(self->child);
|
||||
}
|
||||
|
||||
static void pk_UnaryExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_UnaryExpr* self = (pk_UnaryExpr*)self_;
|
||||
self->child->vt->emit_(self->child, ctx);
|
||||
pk_CodeEmitContext__emit_(ctx, self->opcode, BC_NOARG, self->line);
|
||||
}
|
||||
|
||||
pk_UnaryExpr* pk_UnaryExpr__new(pk_Expr* child, Opcode opcode){
|
||||
static_assert_expr_size(pk_UnaryExpr);
|
||||
pk_UnaryExpr* self = PoolExpr_alloc();
|
||||
self->vt = &UnaryExprVt;
|
||||
self->line = -1;
|
||||
self->child = child;
|
||||
self->opcode = opcode;
|
||||
return self;
|
||||
}
|
||||
|
||||
static pk_ExprVt RawStringExprVt;
|
||||
|
||||
void pk_RawStringExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_RawStringExpr* self = (pk_RawStringExpr*)self_;
|
||||
int index = pk_CodeEmitContext__add_const_string(ctx, self->value);
|
||||
pk_CodeEmitContext__emit_(ctx, OP_LOAD_CONST, index, self->line);
|
||||
pk_CodeEmitContext__emit_(ctx, self->opcode, BC_NOARG, self->line);
|
||||
}
|
||||
|
||||
pk_RawStringExpr* pk_RawStringExpr__new(c11_string value, Opcode opcode){
|
||||
static_assert_expr_size(pk_RawStringExpr);
|
||||
pk_RawStringExpr* self = PoolExpr_alloc();
|
||||
self->vt = &RawStringExprVt;
|
||||
self->line = -1;
|
||||
self->value = value;
|
||||
self->opcode = opcode;
|
||||
return self;
|
||||
}
|
||||
|
||||
static pk_ExprVt ImagExprVt;
|
||||
|
||||
void pk_ImagExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_ImagExpr* self = (pk_ImagExpr*)self_;
|
||||
PyVar value;
|
||||
py_newfloat(&value, self->value);
|
||||
int index = pk_CodeEmitContext__add_const(ctx, &value);
|
||||
pk_CodeEmitContext__emit_(ctx, OP_LOAD_CONST, index, self->line);
|
||||
pk_CodeEmitContext__emit_(ctx, OP_BUILD_IMAG, BC_NOARG, self->line);
|
||||
}
|
||||
|
||||
pk_ImagExpr* pk_ImagExpr__new(double value){
|
||||
static_assert_expr_size(pk_ImagExpr);
|
||||
pk_ImagExpr* self = PoolExpr_alloc();
|
||||
self->vt = &ImagExprVt;
|
||||
self->line = -1;
|
||||
self->value = value;
|
||||
return self;
|
||||
}
|
||||
|
||||
static pk_ExprVt LiteralExprVt;
|
||||
|
||||
void pk_LiteralExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_LiteralExpr* self = (pk_LiteralExpr*)self_;
|
||||
switch(self->value->index){
|
||||
case TokenValue_I64: {
|
||||
int64_t val = self->value->_i64;
|
||||
pk_CodeEmitContext__emit_int(ctx, val, self->line);
|
||||
break;
|
||||
}
|
||||
case TokenValue_F64: {
|
||||
PyVar value;
|
||||
py_newfloat(&value, self->value->_f64);
|
||||
int index = pk_CodeEmitContext__add_const(ctx, &value);
|
||||
pk_CodeEmitContext__emit_(ctx, OP_LOAD_CONST, index, self->line);
|
||||
break;
|
||||
}
|
||||
case TokenValue_STR: {
|
||||
c11_string sv = py_Str__sv(&self->value->_str);
|
||||
int index = pk_CodeEmitContext__add_const_string(ctx, sv);
|
||||
pk_CodeEmitContext__emit_(ctx, OP_LOAD_CONST, index, self->line);
|
||||
break;
|
||||
}
|
||||
default: PK_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
pk_LiteralExpr* pk_LiteralExpr__new(const TokenValue* value){
|
||||
static_assert_expr_size(pk_LiteralExpr);
|
||||
pk_LiteralExpr* self = PoolExpr_alloc();
|
||||
self->vt = &LiteralExprVt;
|
||||
self->line = -1;
|
||||
self->value = value;
|
||||
return self;
|
||||
}
|
||||
|
||||
static pk_ExprVt SliceExprVt;
|
||||
|
||||
void pk_SliceExpr__dtor(pk_Expr* self_){
|
||||
pk_SliceExpr* self = (pk_SliceExpr*)self_;
|
||||
pk_Expr__delete(self->start);
|
||||
pk_Expr__delete(self->stop);
|
||||
pk_Expr__delete(self->step);
|
||||
}
|
||||
|
||||
void pk_SliceExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_SliceExpr* self = (pk_SliceExpr*)self_;
|
||||
if(self->start) self->start->vt->emit_(self->start, ctx);
|
||||
else pk_CodeEmitContext__emit_(ctx, OP_LOAD_NONE, BC_NOARG, self->line);
|
||||
if(self->stop) self->stop->vt->emit_(self->stop, ctx);
|
||||
else pk_CodeEmitContext__emit_(ctx, OP_LOAD_NONE, BC_NOARG, self->line);
|
||||
if(self->step) self->step->vt->emit_(self->step, ctx);
|
||||
else pk_CodeEmitContext__emit_(ctx, OP_LOAD_NONE, BC_NOARG, self->line);
|
||||
pk_CodeEmitContext__emit_(ctx, OP_BUILD_SLICE, BC_NOARG, self->line);
|
||||
}
|
||||
|
||||
pk_SliceExpr* pk_SliceExpr__new(){
|
||||
static_assert_expr_size(pk_SliceExpr);
|
||||
pk_SliceExpr* self = PoolExpr_alloc();
|
||||
self->vt = &SliceExprVt;
|
||||
self->line = -1;
|
||||
self->start = NULL;
|
||||
self->stop = NULL;
|
||||
self->step = NULL;
|
||||
return self;
|
||||
}
|
||||
|
||||
static pk_ExprVt ListExprVt;
|
||||
static pk_ExprVt DictExprVt;
|
||||
static pk_ExprVt SetExprVt;
|
||||
static pk_ExprVt TupleExprVt;
|
||||
|
||||
pk_SequenceExpr* pk_SequenceExpr__new(pk_ExprVt* vt, int count, Opcode opcode){
|
||||
static_assert_expr_size(pk_SequenceExpr);
|
||||
pk_SequenceExpr* self = PoolExpr_alloc();
|
||||
self->vt = vt;
|
||||
self->line = -1;
|
||||
self->opcode = opcode;
|
||||
c11_array__ctor(&self->items, count, sizeof(pk_Expr*));
|
||||
return self;
|
||||
}
|
||||
|
||||
static void pk_SequenceExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_SequenceExpr* self = (pk_SequenceExpr*)self_;
|
||||
for(int i=0; i<self->items.count; i++){
|
||||
pk_Expr* item = c11__getitem(pk_Expr*, &self->items, i);
|
||||
item->vt->emit_(item, ctx);
|
||||
}
|
||||
pk_CodeEmitContext__emit_(ctx, self->opcode, self->items.count, self->line);
|
||||
}
|
||||
|
||||
void pk_SequenceExpr__dtor(pk_Expr* self_){
|
||||
pk_SequenceExpr* self = (pk_SequenceExpr*)self_;
|
||||
c11__foreach(pk_Expr*, &self->items, e){
|
||||
pk_Expr__delete(*e);
|
||||
}
|
||||
c11_array__dtor(&self->items);
|
||||
}
|
||||
|
||||
bool pk_TupleExpr__emit_store(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_SequenceExpr* self = (pk_SequenceExpr*)self_;
|
||||
// TOS is an iterable
|
||||
// items may contain StarredExpr, we should check it
|
||||
int starred_i = -1;
|
||||
for(int i = 0; i < self->items.count; i++) {
|
||||
pk_Expr* e = c11__getitem(pk_Expr*, &self->items, i);
|
||||
if(e->vt->star_level(e) == 0) continue;
|
||||
if(starred_i == -1) starred_i = i;
|
||||
else return false; // multiple StarredExpr not allowed
|
||||
}
|
||||
|
||||
if(starred_i == -1) {
|
||||
Bytecode* prev = c11__at(Bytecode, &ctx->co->codes, ctx->co->codes.count - 1);
|
||||
if(prev->op == OP_BUILD_TUPLE && prev->arg == self->items.count) {
|
||||
// build tuple and unpack it is meaningless
|
||||
pk_CodeEmitContext__revert_last_emit_(ctx);
|
||||
} else {
|
||||
if(prev->op == OP_FOR_ITER) {
|
||||
prev->op = OP_FOR_ITER_UNPACK;
|
||||
prev->arg = self->items.count;
|
||||
} else {
|
||||
pk_CodeEmitContext__emit_(ctx, OP_UNPACK_SEQUENCE, self->items.count, self->line);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// starred assignment target must be in a tuple
|
||||
if(self->items.count == 1) return false;
|
||||
// starred assignment target must be the last one (differ from cpython)
|
||||
if(starred_i != self->items.count - 1) return false;
|
||||
// a,*b = [1,2,3]
|
||||
// stack is [1,2,3] -> [1,[2,3]]
|
||||
pk_CodeEmitContext__emit_(ctx, OP_UNPACK_EX, self->items.count - 1, self->line);
|
||||
}
|
||||
// do reverse emit
|
||||
for(int i = self->items.count - 1; i >= 0; i--) {
|
||||
pk_Expr* e = c11__getitem(pk_Expr*, &self->items, i);
|
||||
bool ok = e->vt->emit_store(e, ctx);
|
||||
if(!ok) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pk_TupleExpr__emit_del(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_SequenceExpr* self = (pk_SequenceExpr*)self_;
|
||||
c11__foreach(pk_Expr*, &self->items, e){
|
||||
bool ok = (*e)->vt->emit_del(*e, ctx);
|
||||
if(!ok) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static pk_ExprVt CompExprVt;
|
||||
|
||||
void pk_CompExpr__dtor(pk_Expr* self_){
|
||||
pk_CompExpr* self = (pk_CompExpr*)self_;
|
||||
pk_Expr__delete(self->expr);
|
||||
pk_Expr__delete(self->vars);
|
||||
pk_Expr__delete(self->iter);
|
||||
pk_Expr__delete(self->cond);
|
||||
}
|
||||
|
||||
void pk_CompExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_CompExpr* self = (pk_CompExpr*)self_;
|
||||
pk_CodeEmitContext__emit_(ctx, self->op0, 0, self->line);
|
||||
self->iter->vt->emit_(self->iter, ctx);
|
||||
pk_CodeEmitContext__emit_(ctx, OP_GET_ITER, BC_NOARG, BC_KEEPLINE);
|
||||
pk_CodeEmitContext__enter_block(ctx, CodeBlockType_FOR_LOOP);
|
||||
int curr_iblock = ctx->curr_iblock;
|
||||
int for_codei = pk_CodeEmitContext__emit_(ctx, OP_FOR_ITER, curr_iblock, BC_KEEPLINE);
|
||||
bool ok = self->vars->vt->emit_store(self->vars, ctx);
|
||||
// this error occurs in `vars` instead of this line, but...nevermind
|
||||
assert(ok); // this should raise a SyntaxError, but we just assert it
|
||||
pk_CodeEmitContext__try_merge_for_iter_store(ctx, for_codei);
|
||||
if(self->cond) {
|
||||
self->cond->vt->emit_(self->cond, ctx);
|
||||
int patch = pk_CodeEmitContext__emit_(ctx, OP_POP_JUMP_IF_FALSE, BC_NOARG, BC_KEEPLINE);
|
||||
self->expr->vt->emit_(self->expr, ctx);
|
||||
pk_CodeEmitContext__emit_(ctx, self->op1, BC_NOARG, BC_KEEPLINE);
|
||||
pk_CodeEmitContext__patch_jump(ctx, patch);
|
||||
} else {
|
||||
self->expr->vt->emit_(self->expr, ctx);
|
||||
pk_CodeEmitContext__emit_(ctx, self->op1, BC_NOARG, BC_KEEPLINE);
|
||||
}
|
||||
pk_CodeEmitContext__emit_(ctx, OP_LOOP_CONTINUE, curr_iblock, BC_KEEPLINE);
|
||||
pk_CodeEmitContext__exit_block(ctx);
|
||||
}
|
||||
|
||||
pk_CompExpr* pk_CompExpr__new(Opcode op0, Opcode op1){
|
||||
static_assert_expr_size(pk_CompExpr);
|
||||
pk_CompExpr* self = PoolExpr_alloc();
|
||||
self->vt = &CompExprVt;
|
||||
self->line = -1;
|
||||
self->op0 = op0;
|
||||
self->op1 = op1;
|
||||
self->expr = NULL;
|
||||
self->vars = NULL;
|
||||
self->iter = NULL;
|
||||
self->cond = NULL;
|
||||
return self;
|
||||
}
|
||||
|
||||
static pk_ExprVt LambdaExprVt;
|
||||
|
||||
pk_LambdaExpr* pk_LambdaExpr__new(int index){
|
||||
static_assert_expr_size(pk_LambdaExpr);
|
||||
pk_LambdaExpr* self = PoolExpr_alloc();
|
||||
self->vt = &LambdaExprVt;
|
||||
self->line = -1;
|
||||
self->index = index;
|
||||
return self;
|
||||
}
|
||||
|
||||
static void pk_LambdaExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_LambdaExpr* self = (pk_LambdaExpr*)self_;
|
||||
pk_CodeEmitContext__emit_(ctx, OP_LOAD_FUNCTION, self->index, self->line);
|
||||
}
|
||||
|
||||
static pk_ExprVt FStringExprVt;
|
||||
|
||||
static bool is_fmt_valid_char(char c) {
|
||||
switch(c) {
|
||||
// clang-format off
|
||||
case '-': case '=': case '*': case '#': case '@': case '!': case '~':
|
||||
case '<': case '>': case '^':
|
||||
case '.': case 'f': case 'd': case 's':
|
||||
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
|
||||
return true;
|
||||
default: return false;
|
||||
// clang-format on
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_identifier(c11_string s) {
|
||||
if(s.size == 0) return false;
|
||||
if(!isalpha(s.data[0]) && s.data[0] != '_') return false;
|
||||
for(int i=0; i<s.size; i++){
|
||||
char c = s.data[i];
|
||||
if(!isalnum(c) && c != '_') return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void _load_simple_expr(pk_CodeEmitContext* ctx, c11_string expr, int line) {
|
||||
bool repr = false;
|
||||
const char* expr_end = expr.data + expr.size;
|
||||
if(expr.size >= 2 && expr_end[-2] == '!') {
|
||||
switch(expr_end[-1]) {
|
||||
case 'r':
|
||||
repr = true;
|
||||
expr.size -= 2; // expr[:-2]
|
||||
break;
|
||||
case 's':
|
||||
repr = false;
|
||||
expr.size -= 2; // expr[:-2]
|
||||
break;
|
||||
default: break; // nothing happens
|
||||
}
|
||||
}
|
||||
// name or name.name
|
||||
bool is_fastpath = false;
|
||||
if(is_identifier(expr)) {
|
||||
// ctx->emit_(OP_LOAD_NAME, StrName(expr.sv()).index, line);
|
||||
pk_CodeEmitContext__emit_(
|
||||
ctx,
|
||||
OP_LOAD_NAME,
|
||||
pk_StrName__map2(expr),
|
||||
line
|
||||
);
|
||||
is_fastpath = true;
|
||||
} else {
|
||||
int dot = c11_string__index(expr, '.');
|
||||
if(dot > 0) {
|
||||
// std::string_view a = expr.sv().substr(0, dot);
|
||||
// std::string_view b = expr.sv().substr(dot + 1);
|
||||
c11_string a = {expr.data, dot}; // expr[:dot]
|
||||
c11_string b = {expr.data+(dot+1), expr.size-(dot+1)}; // expr[dot+1:]
|
||||
if(is_identifier(a) && is_identifier(b)) {
|
||||
pk_CodeEmitContext__emit_(ctx, OP_LOAD_NAME, pk_StrName__map2(a), line);
|
||||
pk_CodeEmitContext__emit_(ctx, OP_LOAD_ATTR, pk_StrName__map2(b), line);
|
||||
is_fastpath = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!is_fastpath) {
|
||||
int index = pk_CodeEmitContext__add_const_string(ctx, expr);
|
||||
pk_CodeEmitContext__emit_(ctx, OP_FSTRING_EVAL, index, line);
|
||||
}
|
||||
|
||||
if(repr) {
|
||||
pk_CodeEmitContext__emit_(ctx, OP_REPR, BC_NOARG, line);
|
||||
}
|
||||
}
|
||||
|
||||
static void pk_FStringExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_FStringExpr* self = (pk_FStringExpr*)self_;
|
||||
int i = 0; // left index
|
||||
int j = 0; // right index
|
||||
int count = 0; // how many string parts
|
||||
bool flag = false; // true if we are in a expression
|
||||
|
||||
const char* src = self->src.data;
|
||||
while(j < self->src.size) {
|
||||
if(flag) {
|
||||
if(src[j] == '}') {
|
||||
// add expression
|
||||
c11_string expr = {src+i, j-i}; // src[i:j]
|
||||
// BUG: ':' is not a format specifier in f"{stack[2:]}"
|
||||
int conon = c11_string__index(expr, ':');
|
||||
if(conon >= 0) {
|
||||
c11_string spec = {expr.data+(conon+1), expr.size-(conon+1)}; // expr[conon+1:]
|
||||
// filter some invalid spec
|
||||
bool ok = true;
|
||||
for(int k = 0; k < spec.size; k++) {
|
||||
char c = spec.data[k];
|
||||
if(!is_fmt_valid_char(c)) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(ok) {
|
||||
expr.size = conon; // expr[:conon]
|
||||
_load_simple_expr(ctx, expr, self->line);
|
||||
// ctx->emit_(OP_FORMAT_STRING, ctx->add_const_string(spec.sv()), line);
|
||||
pk_CodeEmitContext__emit_(ctx, OP_FORMAT_STRING, pk_CodeEmitContext__add_const_string(ctx, spec), self->line);
|
||||
} else {
|
||||
// ':' is not a spec indicator
|
||||
_load_simple_expr(ctx, expr, self->line);
|
||||
}
|
||||
} else {
|
||||
_load_simple_expr(ctx, expr, self->line);
|
||||
}
|
||||
flag = false;
|
||||
count++;
|
||||
}
|
||||
} else {
|
||||
if(src[j] == '{') {
|
||||
// look at next char
|
||||
if(j + 1 < self->src.size && src[j + 1] == '{') {
|
||||
// {{ -> {
|
||||
j++;
|
||||
pk_CodeEmitContext__emit_(
|
||||
ctx,
|
||||
OP_LOAD_CONST,
|
||||
pk_CodeEmitContext__add_const_string(ctx, (c11_string){"{", 1}),
|
||||
self->line
|
||||
);
|
||||
count++;
|
||||
} else {
|
||||
// { -> }
|
||||
flag = true;
|
||||
i = j + 1;
|
||||
}
|
||||
} else if(src[j] == '}') {
|
||||
// look at next char
|
||||
if(j + 1 < self->src.size && src[j + 1] == '}') {
|
||||
// }} -> }
|
||||
j++;
|
||||
pk_CodeEmitContext__emit_(
|
||||
ctx,
|
||||
OP_LOAD_CONST,
|
||||
pk_CodeEmitContext__add_const_string(ctx, (c11_string){"}", 1}),
|
||||
self->line
|
||||
);
|
||||
count++;
|
||||
} else {
|
||||
// } -> error
|
||||
// throw std::runtime_error("f-string: unexpected }");
|
||||
// just ignore
|
||||
}
|
||||
} else {
|
||||
// literal
|
||||
i = j;
|
||||
while(j < self->src.size && src[j] != '{' && src[j] != '}')
|
||||
j++;
|
||||
c11_string literal = {src+i, j-i}; // src[i:j]
|
||||
pk_CodeEmitContext__emit_(
|
||||
ctx,
|
||||
OP_LOAD_CONST,
|
||||
pk_CodeEmitContext__add_const_string(ctx, literal),
|
||||
self->line
|
||||
);
|
||||
count++;
|
||||
continue; // skip j++
|
||||
}
|
||||
}
|
||||
j++;
|
||||
}
|
||||
|
||||
if(flag) {
|
||||
// literal
|
||||
c11_string literal = {src+i, self->src.size-i}; // src[i:]
|
||||
pk_CodeEmitContext__emit_(ctx, OP_LOAD_CONST, pk_CodeEmitContext__add_const_string(ctx, literal), self->line);
|
||||
count++;
|
||||
}
|
||||
pk_CodeEmitContext__emit_(ctx, OP_BUILD_STRING, count, self->line);
|
||||
}
|
||||
|
||||
pk_FStringExpr* pk_FStringExpr__new(c11_string src){
|
||||
static_assert_expr_size(pk_FStringExpr);
|
||||
pk_FStringExpr* self = PoolExpr_alloc();
|
||||
self->vt = &FStringExprVt;
|
||||
self->line = -1;
|
||||
self->src = src;
|
||||
return self;
|
||||
}
|
||||
|
||||
static pk_ExprVt LogicBinaryExpr;
|
||||
|
||||
pk_LogicBinaryExpr* pk_LogicBinaryExpr__new(pk_Expr* lhs, pk_Expr* rhs, Opcode opcode){
|
||||
static_assert_expr_size(pk_LogicBinaryExpr);
|
||||
pk_LogicBinaryExpr* self = PoolExpr_alloc();
|
||||
self->vt = &LogicBinaryExpr;
|
||||
self->line = -1;
|
||||
self->lhs = lhs;
|
||||
self->rhs = rhs;
|
||||
self->opcode = opcode;
|
||||
return self;
|
||||
}
|
||||
|
||||
void pk_LogicBinaryExpr__dtor(pk_Expr* self_){
|
||||
pk_LogicBinaryExpr* self = (pk_LogicBinaryExpr*)self_;
|
||||
pk_Expr__delete(self->lhs);
|
||||
pk_Expr__delete(self->rhs);
|
||||
}
|
||||
|
||||
void pk_LogicBinaryExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_LogicBinaryExpr* self = (pk_LogicBinaryExpr*)self_;
|
||||
self->lhs->vt->emit_(self->lhs, ctx);
|
||||
int patch = pk_CodeEmitContext__emit_(ctx, self->opcode, BC_NOARG, self->line);
|
||||
self->rhs->vt->emit_(self->rhs, ctx);
|
||||
pk_CodeEmitContext__patch_jump(ctx, patch);
|
||||
}
|
||||
|
||||
static pk_ExprVt GroupedExprVt;
|
||||
|
||||
void pk_GroupedExpr__dtor(pk_Expr* self_){
|
||||
pk_GroupedExpr* self = (pk_GroupedExpr*)self_;
|
||||
pk_Expr__delete(self->child);
|
||||
}
|
||||
|
||||
void pk_GroupedExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_GroupedExpr* self = (pk_GroupedExpr*)self_;
|
||||
self->child->vt->emit_(self->child, ctx);
|
||||
}
|
||||
|
||||
bool pk_GroupedExpr__emit_del(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_GroupedExpr* self = (pk_GroupedExpr*)self_;
|
||||
return self->child->vt->emit_del(self->child, ctx);
|
||||
}
|
||||
|
||||
bool pk_GroupedExpr__emit_store(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_GroupedExpr* self = (pk_GroupedExpr*)self_;
|
||||
return self->child->vt->emit_store(self->child, ctx);
|
||||
}
|
||||
|
||||
pk_GroupedExpr* pk_GroupedExpr__new(pk_Expr* child){
|
||||
static_assert_expr_size(pk_GroupedExpr);
|
||||
pk_GroupedExpr* self = PoolExpr_alloc();
|
||||
self->vt = &GroupedExprVt;
|
||||
self->line = -1;
|
||||
self->child = child;
|
||||
return self;
|
||||
}
|
||||
|
||||
static pk_ExprVt BinaryExprVt;
|
||||
|
||||
static void pk_BinaryExpr__dtor(pk_Expr* self_){
|
||||
pk_BinaryExpr* self = (pk_BinaryExpr*)self_;
|
||||
pk_Expr__delete(self->lhs);
|
||||
pk_Expr__delete(self->rhs);
|
||||
}
|
||||
|
||||
static pk_BinaryExpr__is_compare(pk_Expr* self_){
|
||||
pk_BinaryExpr* self = (pk_BinaryExpr*)self_;
|
||||
switch(self->op) {
|
||||
case TK_LT:
|
||||
case TK_LE:
|
||||
case TK_EQ:
|
||||
case TK_NE:
|
||||
case TK_GT:
|
||||
case TK_GE: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void _emit_compare(pk_BinaryExpr* self, pk_CodeEmitContext* ctx, c11_vector* jmps) {
|
||||
if(self->lhs->vt->is_compare(self->lhs)) {
|
||||
pk_BinaryExpr* lhs = (pk_BinaryExpr*)lhs;
|
||||
_emit_compare(lhs, ctx, jmps);
|
||||
} else {
|
||||
self->lhs->vt->emit_(self->lhs, ctx); // [a]
|
||||
}
|
||||
self->rhs->vt->emit_(self->rhs, ctx); // [a, b]
|
||||
pk_CodeEmitContext__emit_(ctx, OP_DUP_TOP, BC_NOARG, self->line); // [a, b, b]
|
||||
pk_CodeEmitContext__emit_(ctx, OP_ROT_THREE, BC_NOARG, self->line); // [b, a, b]
|
||||
Opcode opcode;
|
||||
switch(self->op) {
|
||||
case TK_LT: opcode = OP_COMPARE_LT; break;
|
||||
case TK_LE: opcode = OP_COMPARE_LE; break;
|
||||
case TK_EQ: opcode = OP_COMPARE_EQ; break;
|
||||
case TK_NE: opcode = OP_COMPARE_NE; break;
|
||||
case TK_GT: opcode = OP_COMPARE_GT; break;
|
||||
case TK_GE: opcode = OP_COMPARE_GE; break;
|
||||
default: PK_UNREACHABLE()
|
||||
}
|
||||
pk_CodeEmitContext__emit_(ctx, opcode, BC_NOARG, self->line);
|
||||
// [b, RES]
|
||||
int index = pk_CodeEmitContext__emit_(ctx, OP_JUMP_IF_FALSE_OR_POP, BC_NOARG, self->line);
|
||||
c11_vector__push(int, jmps, index);
|
||||
}
|
||||
|
||||
static void pk_BinaryExpr__emit_(pk_Expr* self_, pk_CodeEmitContext* ctx) {
|
||||
pk_BinaryExpr* self = (pk_BinaryExpr*)self_;
|
||||
c11_vector/*T=int*/ jmps;
|
||||
c11_vector__ctor(&jmps, sizeof(int));
|
||||
if(self->vt->is_compare(self_) && self->lhs->vt->is_compare(self->lhs)) {
|
||||
// (a < b) < c
|
||||
pk_BinaryExpr* e = (pk_BinaryExpr*)self->lhs;
|
||||
_emit_compare(e, ctx, &jmps);
|
||||
// [b, RES]
|
||||
} else {
|
||||
// (1 + 2) < c
|
||||
if(self->inplace) {
|
||||
self->lhs->vt->emit_inplace(self->lhs, ctx);
|
||||
} else {
|
||||
self->lhs->vt->emit_(self->lhs, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
self->rhs->vt->emit_(self->rhs, ctx);
|
||||
Opcode opcode;
|
||||
switch(self->op) {
|
||||
case TK_ADD: opcode = OP_BINARY_ADD; break;
|
||||
case TK_SUB: opcode = OP_BINARY_SUB; break;
|
||||
case TK_MUL: opcode = OP_BINARY_MUL; break;
|
||||
case TK_DIV: opcode = OP_BINARY_TRUEDIV; break;
|
||||
case TK_FLOORDIV: opcode = OP_BINARY_FLOORDIV; break;
|
||||
case TK_MOD: opcode = OP_BINARY_MOD; break;
|
||||
case TK_POW: opcode = OP_BINARY_POW; break;
|
||||
|
||||
case TK_LT: opcode = OP_COMPARE_LT; break;
|
||||
case TK_LE: opcode = OP_COMPARE_LE; break;
|
||||
case TK_EQ: opcode = OP_COMPARE_EQ; break;
|
||||
case TK_NE: opcode = OP_COMPARE_NE; break;
|
||||
case TK_GT: opcode = OP_COMPARE_GT; break;
|
||||
case TK_GE: opcode = OP_COMPARE_GE; break;
|
||||
|
||||
// case TK_IN: ctx->emit_(OP_CONTAINS_OP, 0, line); break;
|
||||
// case TK_NOT_IN: ctx->emit_(OP_CONTAINS_OP, 1, line); break;
|
||||
// case TK_IS: ctx->emit_(OP_IS_OP, BC_NOARG, line); break;
|
||||
// case TK_IS_NOT: ctx->emit_(OP_IS_NOT_OP, BC_NOARG, line); break;
|
||||
|
||||
case TK_LSHIFT: ctx->emit_(OP_BITWISE_LSHIFT, BC_NOARG, line); break;
|
||||
case TK_RSHIFT: ctx->emit_(OP_BITWISE_RSHIFT, BC_NOARG, line); break;
|
||||
case TK_AND: ctx->emit_(OP_BITWISE_AND, BC_NOARG, line); break;
|
||||
case TK_OR: ctx->emit_(OP_BITWISE_OR, BC_NOARG, line); break;
|
||||
case TK_XOR: ctx->emit_(OP_BITWISE_XOR, BC_NOARG, line); break;
|
||||
|
||||
case TK_DECORATOR: ctx->emit_(OP_BINARY_MATMUL, BC_NOARG, line); break;
|
||||
default: PK_FATAL_ERROR("unknown binary operator: %s\n", pk_TokenSymbols[op]);
|
||||
}
|
||||
|
||||
for(int i: jmps)
|
||||
ctx->patch_jump(i);
|
||||
}
|
||||
|
||||
static pk_ExprVt TernaryExprVt;
|
||||
|
||||
/////////////////////////////////////////////
|
||||
void pk_Expr__initialize(){
|
||||
pk_ExprVt__ctor(&NameExprVt);
|
||||
pk_ExprVt* vt = &NameExprVt;
|
||||
vt->emit_ = pk_NameExpr__emit_;
|
||||
vt->emit_del = pk_NameExpr__emit_del;
|
||||
vt->emit_store = pk_NameExpr__emit_store;
|
||||
|
||||
pk_ExprVt__ctor(&StarredExprVt);
|
||||
vt = &StarredExprVt;
|
||||
vt->dtor = pk_UnaryExpr__dtor;
|
||||
vt->star_level = pk_ExprVt__star_level;
|
||||
vt->emit_ = pk_StarredExpr__emit_;
|
||||
vt->emit_store = pk_StarredExpr__emit_store;
|
||||
|
||||
pk_ExprVt__ctor(&UnaryExprVt);
|
||||
vt = &UnaryExprVt;
|
||||
vt->dtor = pk_UnaryExpr__dtor;
|
||||
vt->emit_ = pk_UnaryExpr__emit_;
|
||||
|
||||
pk_ExprVt__ctor(&RawStringExprVt);
|
||||
vt = &RawStringExprVt;
|
||||
vt->emit_ = pk_RawStringExpr__emit_;
|
||||
|
||||
pk_ExprVt__ctor(&ImagExprVt);
|
||||
vt = &ImagExprVt;
|
||||
vt->emit_ = pk_ImagExpr__emit_;
|
||||
|
||||
pk_ExprVt__ctor(&LiteralExprVt);
|
||||
vt = &LiteralExprVt;
|
||||
vt->emit_ = pk_LiteralExpr__emit_;
|
||||
vt->is_literal = true;
|
||||
vt->is_json_object = true;
|
||||
|
||||
pk_ExprVt__ctor(&SliceExprVt);
|
||||
vt = &SliceExprVt;
|
||||
vt->dtor = pk_SliceExpr__dtor;
|
||||
vt->emit_ = pk_SliceExpr__emit_;
|
||||
|
||||
pk_ExprVt* seqVt[] = {&ListExprVt, &DictExprVt, &SetExprVt, &TupleExprVt};
|
||||
for(int i=0; i<4; i++){
|
||||
pk_ExprVt__ctor(seqVt[i]);
|
||||
vt = seqVt[i];
|
||||
vt->dtor = pk_SequenceExpr__dtor;
|
||||
vt->emit_ = pk_SequenceExpr__emit_;
|
||||
}
|
||||
|
||||
ListExprVt.is_json_object = true;
|
||||
DictExprVt.is_json_object = true;
|
||||
|
||||
TupleExprVt.is_tuple = true;
|
||||
TupleExprVt.emit_store = pk_TupleExpr__emit_store;
|
||||
TupleExprVt.emit_del = pk_TupleExpr__emit_del;
|
||||
|
||||
pk_ExprVt__ctor(&CompExprVt);
|
||||
vt = &CompExprVt;
|
||||
vt->dtor = pk_CompExpr__dtor;
|
||||
vt->emit_ = pk_CompExpr__emit_;
|
||||
|
||||
pk_ExprVt__ctor(&LambdaExprVt);
|
||||
vt = &LambdaExprVt;
|
||||
vt->emit_ = pk_LambdaExpr__emit_;
|
||||
|
||||
pk_ExprVt__ctor(&FStringExprVt);
|
||||
vt = &FStringExprVt;
|
||||
vt->emit_ = pk_FStringExpr__emit_;
|
||||
|
||||
pk_ExprVt__ctor(&LogicBinaryExpr);
|
||||
vt = &LogicBinaryExpr;
|
||||
vt->dtor = pk_LogicBinaryExpr__dtor;
|
||||
vt->emit_ = pk_LogicBinaryExpr__emit_;
|
||||
|
||||
pk_ExprVt__ctor(&GroupedExprVt);
|
||||
vt = &GroupedExprVt;
|
||||
vt->dtor = pk_GroupedExpr__dtor;
|
||||
vt->emit_ = pk_GroupedExpr__emit_;
|
||||
vt->emit_del = pk_GroupedExpr__emit_del;
|
||||
vt->emit_store = pk_GroupedExpr__emit_store;
|
||||
}
|
@ -21,18 +21,18 @@ typedef struct pk_Lexer{
|
||||
c11_vector/*T=int*/ indents;
|
||||
} pk_Lexer;
|
||||
|
||||
typedef struct pk_TokenDeserializer {
|
||||
typedef struct TokenDeserializer {
|
||||
const char* curr;
|
||||
const char* source;
|
||||
} pk_TokenDeserializer;
|
||||
} TokenDeserializer;
|
||||
|
||||
void pk_TokenDeserializer__ctor(pk_TokenDeserializer* self, const char* source);
|
||||
bool pk_TokenDeserializer__match_char(pk_TokenDeserializer* self, char c);
|
||||
c11_string pk_TokenDeserializer__read_string(pk_TokenDeserializer* self, char c);
|
||||
py_Str pk_TokenDeserializer__read_string_from_hex(pk_TokenDeserializer* self, char c);
|
||||
int pk_TokenDeserializer__read_count(pk_TokenDeserializer* self);
|
||||
int64_t pk_TokenDeserializer__read_uint(pk_TokenDeserializer* self, char c);
|
||||
double pk_TokenDeserializer__read_float(pk_TokenDeserializer* self, char c);
|
||||
void TokenDeserializer__ctor(TokenDeserializer* self, const char* source);
|
||||
bool TokenDeserializer__match_char(TokenDeserializer* self, char c);
|
||||
c11_string TokenDeserializer__read_string(TokenDeserializer* self, char c);
|
||||
py_Str TokenDeserializer__read_string_from_hex(TokenDeserializer* self, char c);
|
||||
int TokenDeserializer__read_count(TokenDeserializer* self);
|
||||
int64_t TokenDeserializer__read_uint(TokenDeserializer* self, char c);
|
||||
double TokenDeserializer__read_float(TokenDeserializer* self, char c);
|
||||
|
||||
|
||||
const static TokenValue EmptyTokenValue;
|
||||
@ -376,7 +376,7 @@ static Error* eat_number(pk_Lexer* self){
|
||||
return NULL;
|
||||
}
|
||||
// try integer
|
||||
TokenValue value = {.index = TokenValue_EMPTY};
|
||||
TokenValue value = {.index = TokenValue_I64};
|
||||
switch(parse_uint(text, &value._i64, -1)) {
|
||||
case IntParsing_SUCCESS:
|
||||
add_token_with_value(self, TK_NUM, value);
|
||||
@ -553,34 +553,34 @@ static Error* lex_one_token(pk_Lexer* self, bool* eof){
|
||||
}
|
||||
|
||||
static Error* from_precompiled(pk_Lexer* self) {
|
||||
pk_TokenDeserializer deserializer;
|
||||
pk_TokenDeserializer__ctor(&deserializer, py_Str__data(&self->src->source));
|
||||
TokenDeserializer deserializer;
|
||||
TokenDeserializer__ctor(&deserializer, py_Str__data(&self->src->source));
|
||||
|
||||
deserializer.curr += 5; // skip "pkpy:"
|
||||
c11_string version = pk_TokenDeserializer__read_string(&deserializer, '\n');
|
||||
c11_string version = TokenDeserializer__read_string(&deserializer, '\n');
|
||||
|
||||
if(c11_string__cmp3(version, PK_VERSION) != 0) {
|
||||
return SyntaxError("precompiled version mismatch");
|
||||
}
|
||||
if(pk_TokenDeserializer__read_uint(&deserializer, '\n') != (int64_t)self->src->mode){
|
||||
if(TokenDeserializer__read_uint(&deserializer, '\n') != (int64_t)self->src->mode){
|
||||
return SyntaxError("precompiled mode mismatch");
|
||||
}
|
||||
|
||||
int count = pk_TokenDeserializer__read_count(&deserializer);
|
||||
int count = TokenDeserializer__read_count(&deserializer);
|
||||
c11_vector* precompiled_tokens = &self->src->_precompiled_tokens;
|
||||
for(int i = 0; i < count; i++) {
|
||||
c11_string item = pk_TokenDeserializer__read_string(&deserializer, '\n');
|
||||
c11_string item = TokenDeserializer__read_string(&deserializer, '\n');
|
||||
py_Str copied_item;
|
||||
py_Str__ctor2(&copied_item, item.data, item.size);
|
||||
c11_vector__push(py_Str, precompiled_tokens, copied_item);
|
||||
}
|
||||
|
||||
count = pk_TokenDeserializer__read_count(&deserializer);
|
||||
count = TokenDeserializer__read_count(&deserializer);
|
||||
for(int i = 0; i < count; i++) {
|
||||
Token t;
|
||||
t.type = (TokenIndex)pk_TokenDeserializer__read_uint(&deserializer, ',');
|
||||
t.type = (TokenIndex)TokenDeserializer__read_uint(&deserializer, ',');
|
||||
if(is_raw_string_used(t.type)) {
|
||||
int64_t index = pk_TokenDeserializer__read_uint(&deserializer, ',');
|
||||
int64_t index = TokenDeserializer__read_uint(&deserializer, ',');
|
||||
py_Str* p = c11__at(py_Str, precompiled_tokens, index);
|
||||
t.start = py_Str__data(p);
|
||||
t.length = c11__getitem(py_Str, precompiled_tokens, index).size;
|
||||
@ -589,30 +589,30 @@ static Error* from_precompiled(pk_Lexer* self) {
|
||||
t.length = 0;
|
||||
}
|
||||
|
||||
if(pk_TokenDeserializer__match_char(&deserializer, ',')) {
|
||||
if(TokenDeserializer__match_char(&deserializer, ',')) {
|
||||
t.line = c11_vector__back(Token, &self->nexts).line;
|
||||
} else {
|
||||
t.line = (int)pk_TokenDeserializer__read_uint(&deserializer, ',');
|
||||
t.line = (int)TokenDeserializer__read_uint(&deserializer, ',');
|
||||
}
|
||||
|
||||
if(pk_TokenDeserializer__match_char(&deserializer, ',')) {
|
||||
if(TokenDeserializer__match_char(&deserializer, ',')) {
|
||||
t.brackets_level = c11_vector__back(Token, &self->nexts).brackets_level;
|
||||
} else {
|
||||
t.brackets_level = (int)pk_TokenDeserializer__read_uint(&deserializer, ',');
|
||||
t.brackets_level = (int)TokenDeserializer__read_uint(&deserializer, ',');
|
||||
}
|
||||
|
||||
char type = (*deserializer.curr++); // read_char
|
||||
switch(type) {
|
||||
case 'I': {
|
||||
int64_t res = pk_TokenDeserializer__read_uint(&deserializer, '\n');
|
||||
int64_t res = TokenDeserializer__read_uint(&deserializer, '\n');
|
||||
t.value = (TokenValue){TokenValue_I64, ._i64 = res};
|
||||
} break;
|
||||
case 'F': {
|
||||
double res = pk_TokenDeserializer__read_float(&deserializer, '\n');
|
||||
double res = TokenDeserializer__read_float(&deserializer, '\n');
|
||||
t.value = (TokenValue){TokenValue_F64, ._f64 = res};
|
||||
} break;
|
||||
case 'S': {
|
||||
py_Str res = pk_TokenDeserializer__read_string_from_hex(&deserializer, '\n');
|
||||
py_Str res = TokenDeserializer__read_string_from_hex(&deserializer, '\n');
|
||||
t.value = (TokenValue){TokenValue_STR, ._str = res};
|
||||
} break;
|
||||
default:
|
||||
@ -875,12 +875,12 @@ const char* pk_TokenSymbols[] = {
|
||||
"try", "while", "with", "yield",
|
||||
};
|
||||
|
||||
void pk_TokenDeserializer__ctor(pk_TokenDeserializer* self, const char* source){
|
||||
void TokenDeserializer__ctor(TokenDeserializer* self, const char* source){
|
||||
self->curr = source;
|
||||
self->source = source;
|
||||
}
|
||||
|
||||
bool pk_TokenDeserializer__match_char(pk_TokenDeserializer* self, char c){
|
||||
bool TokenDeserializer__match_char(TokenDeserializer* self, char c){
|
||||
if(*self->curr == c) {
|
||||
self->curr++;
|
||||
return true;
|
||||
@ -888,7 +888,7 @@ bool pk_TokenDeserializer__match_char(pk_TokenDeserializer* self, char c){
|
||||
return false;
|
||||
}
|
||||
|
||||
c11_string pk_TokenDeserializer__read_string(pk_TokenDeserializer* self, char c){
|
||||
c11_string TokenDeserializer__read_string(TokenDeserializer* self, char c){
|
||||
const char* start = self->curr;
|
||||
while(*self->curr != c)
|
||||
self->curr++;
|
||||
@ -897,8 +897,8 @@ c11_string pk_TokenDeserializer__read_string(pk_TokenDeserializer* self, char c)
|
||||
return retval;
|
||||
}
|
||||
|
||||
py_Str pk_TokenDeserializer__read_string_from_hex(pk_TokenDeserializer* self, char c){
|
||||
c11_string sv = pk_TokenDeserializer__read_string(self, c);
|
||||
py_Str TokenDeserializer__read_string_from_hex(TokenDeserializer* self, char c){
|
||||
c11_string sv = TokenDeserializer__read_string(self, c);
|
||||
const char* s = sv.data;
|
||||
char* buffer = (char*)malloc(sv.size / 2 + 1);
|
||||
for(int i = 0; i < sv.size; i += 2) {
|
||||
@ -927,13 +927,13 @@ py_Str pk_TokenDeserializer__read_string_from_hex(pk_TokenDeserializer* self, ch
|
||||
};
|
||||
}
|
||||
|
||||
int pk_TokenDeserializer__read_count(pk_TokenDeserializer* self){
|
||||
int TokenDeserializer__read_count(TokenDeserializer* self){
|
||||
assert(*self->curr == '=');
|
||||
self->curr++;
|
||||
return pk_TokenDeserializer__read_uint(self, '\n');
|
||||
return TokenDeserializer__read_uint(self, '\n');
|
||||
}
|
||||
|
||||
int64_t pk_TokenDeserializer__read_uint(pk_TokenDeserializer* self, char c){
|
||||
int64_t TokenDeserializer__read_uint(TokenDeserializer* self, char c){
|
||||
int64_t out = 0;
|
||||
while(*self->curr != c) {
|
||||
out = out * 10 + (*self->curr - '0');
|
||||
@ -943,8 +943,8 @@ int64_t pk_TokenDeserializer__read_uint(pk_TokenDeserializer* self, char c){
|
||||
return out;
|
||||
}
|
||||
|
||||
double pk_TokenDeserializer__read_float(pk_TokenDeserializer* self, char c){
|
||||
c11_string sv = pk_TokenDeserializer__read_string(self, c);
|
||||
double TokenDeserializer__read_float(TokenDeserializer* self, char c){
|
||||
c11_string sv = TokenDeserializer__read_string(self, c);
|
||||
py_Str nullterm;
|
||||
py_Str__ctor2(&nullterm, sv.data, sv.size);
|
||||
char* end;
|
||||
|
File diff suppressed because it is too large
Load Diff
1151
src/interpreter/ceval.cpp
Normal file
1151
src/interpreter/ceval.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -10,16 +10,16 @@ void ValueStack__clear(ValueStack* self) {
|
||||
self->sp = self->begin;
|
||||
}
|
||||
|
||||
PyVar* FastLocals__try_get_by_name(PyVar* locals, const CodeObject* co, py_Name name){
|
||||
py_TValue* FastLocals__try_get_by_name(py_TValue* locals, const CodeObject* co, py_Name name){
|
||||
int index = c11_smallmap_n2i__get(&co->varnames_inv, name, -1);
|
||||
if(index == -1) return NULL;
|
||||
return &locals[index];
|
||||
}
|
||||
|
||||
pk_NameDict* FastLocals__to_namedict(PyVar* locals, const CodeObject* co) {
|
||||
pk_NameDict* FastLocals__to_namedict(py_TValue* locals, const CodeObject* co) {
|
||||
pk_NameDict* dict = pk_NameDict__new();
|
||||
c11__foreach(c11_smallmap_n2i_KV, &co->varnames_inv, entry) {
|
||||
PyVar value = locals[entry->value];
|
||||
py_TValue value = locals[entry->value];
|
||||
if(!py_isnull(&value)){
|
||||
pk_NameDict__set(dict, entry->key, value);
|
||||
}
|
||||
@ -39,14 +39,14 @@ void UnwindTarget__delete(UnwindTarget* self){
|
||||
free(self);
|
||||
}
|
||||
|
||||
Frame* Frame__new(const CodeObject* co, const PyVar* module, const PyVar* function, PyVar* p0, PyVar* locals, const CodeObject* locals_co){
|
||||
Frame* Frame__new(const CodeObject* co, const py_TValue* module, const py_TValue* function, py_TValue* p0, py_TValue* locals, const CodeObject* locals_co){
|
||||
static_assert(sizeof(Frame) <= kPoolFrameBlockSize, "!(sizeof(Frame) <= kPoolFrameBlockSize)");
|
||||
Frame* self = PoolFrame_alloc();
|
||||
self->f_back = NULL;
|
||||
self->ip = (Bytecode*)co->codes.data - 1;
|
||||
self->co = co;
|
||||
self->module = module->_obj;
|
||||
self->function = function->_obj;
|
||||
self->function = function ? function->_obj : NULL;
|
||||
self->p0 = p0;
|
||||
self->locals = locals;
|
||||
self->locals_co = locals_co;
|
||||
@ -72,7 +72,7 @@ int Frame__prepare_jump_exception_handler(Frame* self, ValueStack* _s){
|
||||
iblock = block->parent;
|
||||
}
|
||||
if(iblock < 0) return -1;
|
||||
PyVar obj = *--_s->sp; // pop exception object
|
||||
py_TValue obj = *--_s->sp; // pop exception object
|
||||
UnwindTarget* uw = Frame__find_unwind_target(self, iblock);
|
||||
_s->sp = (self->locals + uw->offset); // unwind the stack
|
||||
*(_s->sp++) = obj; // push it back
|
||||
@ -121,7 +121,7 @@ UnwindTarget* Frame__find_unwind_target(Frame* self, int iblock){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Frame__set_unwind_target(Frame* self, PyVar* sp) {
|
||||
void Frame__set_unwind_target(Frame* self, py_TValue* sp) {
|
||||
int iblock = Frame__iblock(self);
|
||||
UnwindTarget* existing = Frame__find_unwind_target(self, iblock);
|
||||
if(existing) {
|
||||
@ -131,3 +131,11 @@ void Frame__set_unwind_target(Frame* self, PyVar* sp) {
|
||||
self->uw_list = UnwindTarget__new(prev, iblock, sp - self->locals);
|
||||
}
|
||||
}
|
||||
|
||||
py_TValue* Frame__f_closure_try_get(Frame* self, StrName name){
|
||||
// if(self->function == NULL) return NULL;
|
||||
// pkpy::Function* fn = PyObject__as(pkpy::Function, self->function);
|
||||
// if(fn->_closure == nullptr) return nullptr;
|
||||
// return pk_NameDict__try_get(fn->_closure, name);
|
||||
return NULL;
|
||||
}
|
@ -119,7 +119,7 @@ PyObject* PyObject__new(py_Type type, int slots, int size){
|
||||
// initialize slots or dict
|
||||
void* p = (char*)self + 8;
|
||||
if(slots >= 0){
|
||||
memset(p, 0, slots*sizeof(PyVar));
|
||||
memset(p, 0, slots*sizeof(py_TValue));
|
||||
}else{
|
||||
pk_NameDict__ctor(p);
|
||||
}
|
||||
|
@ -1,14 +0,0 @@
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
int py_eq(const py_Ref lhs, const py_Ref rhs){
|
||||
return 0;
|
||||
}
|
||||
|
||||
int py_le(const py_Ref lhs, const py_Ref rhs){
|
||||
return 0;
|
||||
}
|
||||
|
||||
int py_hash(const py_Ref self, int64_t* out){
|
||||
return 0;
|
||||
}
|
@ -7,17 +7,23 @@ static unsigned char* pk_default_import_file(const char* path){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void pk_default_stdout(const char* s){
|
||||
fprintf(stdout, "%s", s);
|
||||
static void pk_default_stdout(const char* fmt, ...){
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vfprintf(stdout, fmt, args);
|
||||
va_end(args);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void pk_default_stderr(const char* s){
|
||||
fprintf(stderr, "%s", s);
|
||||
static void pk_default_stderr(const char* fmt, ...){
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
void pk_TypeInfo__ctor(pk_TypeInfo *self, py_Name name, py_Type base, PyObject* obj, const PyVar* module, bool subclass_enabled){
|
||||
void pk_TypeInfo__ctor(pk_TypeInfo *self, py_Name name, py_Type base, PyObject* obj, const py_TValue* module, bool subclass_enabled){
|
||||
memset(self, 0, sizeof(pk_TypeInfo));
|
||||
|
||||
self->name = name;
|
||||
@ -50,6 +56,7 @@ void pk_VM__ctor(pk_VM* self){
|
||||
self->_stderr = pk_default_stderr;
|
||||
|
||||
self->last_error = NULL;
|
||||
self->last_retval = PY_NULL;
|
||||
|
||||
self->__curr_class = NULL;
|
||||
self->__cached_object_new = NULL;
|
||||
@ -58,19 +65,19 @@ void pk_VM__ctor(pk_VM* self){
|
||||
pk_ManagedHeap__ctor(&self->heap, self);
|
||||
ValueStack__ctor(&self->stack);
|
||||
|
||||
self->True = (PyVar){.type=tp_bool, .is_ptr=true, .extra=1,
|
||||
self->True = (py_TValue){.type=tp_bool, .is_ptr=true, .extra=1,
|
||||
._obj=pk_ManagedHeap__gcnew(&self->heap, tp_bool, 0, 0),
|
||||
};
|
||||
self->False = (PyVar){.type=tp_bool, .is_ptr=true, .extra=0,
|
||||
self->False = (py_TValue){.type=tp_bool, .is_ptr=true, .extra=0,
|
||||
._obj=pk_ManagedHeap__gcnew(&self->heap, tp_bool, 0, 0),
|
||||
};
|
||||
self->None = (PyVar){.type=tp_none_type, .is_ptr=true,
|
||||
self->None = (py_TValue){.type=tp_none_type, .is_ptr=true,
|
||||
._obj=pk_ManagedHeap__gcnew(&self->heap, tp_none_type, 0, 0),
|
||||
};
|
||||
self->NotImplemented = (PyVar){.type=tp_not_implemented_type, .is_ptr=true,
|
||||
self->NotImplemented = (py_TValue){.type=tp_not_implemented_type, .is_ptr=true,
|
||||
._obj=pk_ManagedHeap__gcnew(&self->heap, tp_not_implemented_type, 0, 0),
|
||||
};
|
||||
self->Ellipsis = (PyVar){.type=tp_ellipsis, .is_ptr=true,
|
||||
self->Ellipsis = (py_TValue){.type=tp_ellipsis, .is_ptr=true,
|
||||
._obj=pk_ManagedHeap__gcnew(&self->heap, tp_ellipsis, 0, 0),
|
||||
};
|
||||
|
||||
@ -147,7 +154,9 @@ void pk_VM__ctor(pk_VM* self){
|
||||
}
|
||||
|
||||
void pk_VM__dtor(pk_VM* self){
|
||||
PK_DECREF(self->__dynamic_func_decl);
|
||||
if(self->__dynamic_func_decl){
|
||||
PK_DECREF(self->__dynamic_func_decl);
|
||||
}
|
||||
// destroy all objects
|
||||
pk_ManagedHeap__dtor(&self->heap);
|
||||
// clear frames
|
||||
@ -165,15 +174,14 @@ void pk_VM__push_frame(pk_VM* self, Frame* frame){
|
||||
void pk_VM__pop_frame(pk_VM* self){
|
||||
assert(self->top_frame);
|
||||
Frame* frame = self->top_frame;
|
||||
// reset stack pointer
|
||||
self->stack.sp = frame->p0;
|
||||
// pop frame and delete
|
||||
self->top_frame = frame->f_back;
|
||||
Frame__delete(frame);
|
||||
}
|
||||
|
||||
pk_FrameResult pk_VM__run_top_frame(pk_VM* self){
|
||||
return RES_RETURN;
|
||||
}
|
||||
|
||||
py_Type pk_VM__new_type(pk_VM* self, const char* name, py_Type base, const PyVar* module, bool subclass_enabled){
|
||||
py_Type pk_VM__new_type(pk_VM* self, const char* name, py_Type base, const py_TValue* module, bool subclass_enabled){
|
||||
py_Type type = self->types.count;
|
||||
pk_TypeInfo* ti = c11_vector__emplace(&self->types);
|
||||
PyObject* typeobj = pk_ManagedHeap__gcnew(&self->heap, tp_type, -1, sizeof(py_Type));
|
||||
@ -185,7 +193,7 @@ py_Type pk_VM__new_type(pk_VM* self, const char* name, py_Type base, const PyVar
|
||||
|
||||
/****************************************/
|
||||
void PyObject__delete(PyObject *self){
|
||||
pk_TypeInfo* ti = c11__getitem(pk_TypeInfo*, &pk_current_vm->types, self->type);
|
||||
pk_TypeInfo* ti = c11__at(pk_TypeInfo, &pk_current_vm->types, self->type);
|
||||
if(ti->dtor) ti->dtor(PyObject__value(self));
|
||||
if(self->slots == -1) pk_NameDict__dtor(PyObject__dict(self));
|
||||
if(self->gc_is_large){
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "pocketpy/objects/base.h"
|
||||
|
||||
PyVar PY_NULL = {.type=0, .is_ptr=false, .extra=0, ._i64=0};
|
||||
PyVar PY_OP_CALL = {.type=27, .is_ptr=false, .extra=0, ._i64=0};
|
||||
PyVar PY_OP_YIELD = {.type=28, .is_ptr=false, .extra=0, ._i64=0};
|
||||
py_TValue PY_NULL = {.type=0, .is_ptr=false, .extra=0, ._i64=0};
|
||||
py_TValue PY_OP_CALL = {.type=27, .is_ptr=false, .extra=0, ._i64=0};
|
||||
py_TValue PY_OP_YIELD = {.type=28, .is_ptr=false, .extra=0, ._i64=0};
|
||||
|
||||
|
@ -13,7 +13,7 @@ bool Bytecode__is_forward_jump(const Bytecode* self) {
|
||||
return self->op >= OP_JUMP_FORWARD && self->op <= OP_LOOP_BREAK;
|
||||
}
|
||||
|
||||
FuncDecl_ FuncDecl__rcnew(pk_SourceData_ src, c11_string name){
|
||||
FuncDecl_ FuncDecl__rcnew(pk_SourceData_ src, c11_string name) {
|
||||
FuncDecl* self = malloc(sizeof(FuncDecl));
|
||||
self->rc.count = 1;
|
||||
self->rc.dtor = (void (*)(void*))FuncDecl__dtor;
|
||||
@ -33,27 +33,28 @@ FuncDecl_ FuncDecl__rcnew(pk_SourceData_ src, c11_string name){
|
||||
return self;
|
||||
}
|
||||
|
||||
void FuncDecl__dtor(FuncDecl* self){
|
||||
void FuncDecl__dtor(FuncDecl* self) {
|
||||
CodeObject__dtor(&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){
|
||||
void FuncDecl__add_kwarg(FuncDecl* self, int index, uint16_t key, const py_TValue* value) {
|
||||
c11_smallmap_n2i__set(&self->kw_to_index, key, index);
|
||||
FuncDeclKwArg item = {index, key, *value};
|
||||
c11_vector__push(FuncDeclKwArg, &self->kwargs, item);
|
||||
}
|
||||
|
||||
void CodeObject__ctor(CodeObject* self, pk_SourceData_ src, c11_string name){
|
||||
self->src = src; PK_INCREF(src);
|
||||
void CodeObject__ctor(CodeObject* self, pk_SourceData_ src, c11_string name) {
|
||||
self->src = src;
|
||||
PK_INCREF(src);
|
||||
py_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->consts, sizeof(py_TValue));
|
||||
c11_vector__ctor(&self->varnames, sizeof(uint16_t));
|
||||
self->nlocals = 0;
|
||||
|
||||
@ -70,7 +71,7 @@ void CodeObject__ctor(CodeObject* self, pk_SourceData_ src, c11_string name){
|
||||
c11_vector__push(CodeBlock, &self->blocks, root_block);
|
||||
}
|
||||
|
||||
void CodeObject__dtor(CodeObject* self){
|
||||
void CodeObject__dtor(CodeObject* self) {
|
||||
PK_DECREF(self->src);
|
||||
py_Str__dtor(&self->name);
|
||||
|
||||
@ -85,7 +86,7 @@ void CodeObject__dtor(CodeObject* self){
|
||||
|
||||
c11_vector__dtor(&self->blocks);
|
||||
|
||||
for(int i=0; i<self->func_decls.count; i++){
|
||||
for(int i = 0; i < self->func_decls.count; i++) {
|
||||
FuncDecl_ decl = c11__getitem(FuncDecl_, &self->func_decls, i);
|
||||
PK_DECREF(decl);
|
||||
}
|
||||
|
@ -13,8 +13,8 @@
|
||||
#define pkpy_Var__set_null(self) do { (self)->type = 0; } while(0)
|
||||
|
||||
struct pkpy_DictEntry {
|
||||
PyVar key;
|
||||
PyVar val;
|
||||
py_TValue key;
|
||||
py_TValue val;
|
||||
};
|
||||
|
||||
inline extern int pkpy_Dict__idx_size(const pkpy_Dict* self) {
|
||||
@ -79,7 +79,7 @@ static void pkpy_Dict__htset(pkpy_Dict* self, int h, int v) {
|
||||
#endif
|
||||
}
|
||||
|
||||
static int pkpy_Dict__probe0(const pkpy_Dict* self, PyVar key, int hash) {
|
||||
static int pkpy_Dict__probe0(const pkpy_Dict* self, py_TValue key, int hash) {
|
||||
const int null = pkpy_Dict__idx_null(self);
|
||||
const int mask = self->_htcap - 1;
|
||||
for(int h = hash & mask;; h = DICT_HASH_NEXT(h) & mask) {
|
||||
@ -92,7 +92,7 @@ static int pkpy_Dict__probe0(const pkpy_Dict* self, PyVar key, int hash) {
|
||||
PK_UNREACHABLE();
|
||||
}
|
||||
|
||||
static int pkpy_Dict__probe1(const pkpy_Dict* self, PyVar key, int hash) {
|
||||
static int pkpy_Dict__probe1(const pkpy_Dict* self, py_TValue key, int hash) {
|
||||
const int null = pkpy_Dict__idx_null(self);
|
||||
const int mask = self->_htcap - 1;
|
||||
for(int h = hash & mask;; h = DICT_HASH_NEXT(h) & mask) {
|
||||
@ -124,7 +124,7 @@ static void pkpy_Dict__extendht(pkpy_Dict* self) {
|
||||
}
|
||||
}
|
||||
|
||||
bool pkpy_Dict__set(pkpy_Dict* self, PyVar key, PyVar val) {
|
||||
bool pkpy_Dict__set(pkpy_Dict* self, py_TValue key, py_TValue val) {
|
||||
int64_t out;
|
||||
int err = py_hash(&key, &out);
|
||||
int hash = DICT_HASH_TRANS(out);
|
||||
@ -161,7 +161,7 @@ bool pkpy_Dict__set(pkpy_Dict* self, PyVar key, PyVar val) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pkpy_Dict__contains(const pkpy_Dict* self, PyVar key) {
|
||||
bool pkpy_Dict__contains(const pkpy_Dict* self, py_TValue key) {
|
||||
int64_t out;
|
||||
int err = py_hash(&key, &out);
|
||||
int hash = DICT_HASH_TRANS(out);
|
||||
@ -205,7 +205,7 @@ static bool pkpy_Dict__refactor(pkpy_Dict* self) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_Dict__del(pkpy_Dict* self, PyVar key) {
|
||||
bool pkpy_Dict__del(pkpy_Dict* self, py_TValue key) {
|
||||
int64_t out;
|
||||
int err = py_hash(&key, &out);
|
||||
int hash = DICT_HASH_TRANS(out);
|
||||
@ -220,7 +220,7 @@ bool pkpy_Dict__del(pkpy_Dict* self, PyVar key) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const PyVar *pkpy_Dict__try_get(const pkpy_Dict* self, PyVar key) {
|
||||
const py_TValue *pkpy_Dict__try_get(const pkpy_Dict* self, py_TValue key) {
|
||||
int64_t out;
|
||||
int err = py_hash(&key, &out);
|
||||
int hash = DICT_HASH_TRANS(out);
|
||||
@ -263,7 +263,7 @@ pkpy_DictIter pkpy_Dict__iter(const pkpy_Dict *self) {
|
||||
};
|
||||
}
|
||||
|
||||
bool pkpy_DictIter__next(pkpy_DictIter *self, PyVar *key, PyVar *val) {
|
||||
bool pkpy_DictIter__next(pkpy_DictIter *self, py_TValue *key, py_TValue *val) {
|
||||
if(self->_index >= self->_dict->_entries.count) return false;
|
||||
|
||||
struct pkpy_DictEntry* entry = &c11__getitem(struct pkpy_DictEntry, &self->_dict->_entries, self->_index);
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#define SMALLMAP_T__SOURCE
|
||||
#define K uint16_t
|
||||
#define V PyVar
|
||||
#define V py_TValue
|
||||
#define NAME pk_NameDict
|
||||
#include "pocketpy/xmacros/smallmap.h"
|
||||
#undef SMALLMAP_T__SOURCE
|
||||
|
@ -11,7 +11,7 @@ pk_NameDict* PyObject__dict(PyObject* self){
|
||||
return (pk_NameDict*)((char*)self + 8);
|
||||
}
|
||||
|
||||
PyVar* PyObject__slots(PyObject* self){
|
||||
py_TValue* PyObject__slots(PyObject* self){
|
||||
assert(self->slots >= 0);
|
||||
return (PyVar*)((char*)self + 8);
|
||||
return (py_TValue*)((char*)self + 8);
|
||||
}
|
28
src/public/py_ops.c
Normal file
28
src/public/py_ops.c
Normal file
@ -0,0 +1,28 @@
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
int py_eq(const py_Ref lhs, const py_Ref rhs) { return 0; }
|
||||
|
||||
int py_le(const py_Ref lhs, const py_Ref rhs) { return 0; }
|
||||
|
||||
int py_hash(const py_Ref val, int64_t* out) { return 0; }
|
||||
|
||||
int py_str(const py_Ref val) { return 0; }
|
||||
|
||||
int py_repr(const py_Ref val) {
|
||||
const pk_TypeInfo* ti = c11__at(pk_TypeInfo, &pk_current_vm->types, val->type);
|
||||
if(ti->m__repr__) return ti->m__repr__(1, val);
|
||||
return py_callmethod(val, __repr__);
|
||||
}
|
||||
|
||||
int py_getattr(const py_Ref self, py_Name name, py_Ref out){
|
||||
return -1;
|
||||
}
|
||||
|
||||
int py_setattr(py_Ref self, py_Name name, const py_Ref val){
|
||||
return -1;
|
||||
}
|
||||
|
||||
int py_callmethod(py_Ref self, py_Name name, ...){
|
||||
return -1;
|
||||
}
|
25
src/public/py_tuple.c
Normal file
25
src/public/py_tuple.c
Normal file
@ -0,0 +1,25 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
void py_newtuple(py_Ref out, int n) {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
PyObject* obj = pk_ManagedHeap__gcnew(&vm->heap, tp_tuple, n, 0);
|
||||
out->type = tp_tuple;
|
||||
out->is_ptr = true;
|
||||
out->_obj = obj;
|
||||
}
|
||||
|
||||
py_Ref py_tuple__getitem(const py_Ref self, int i){
|
||||
return py_getslot(self, i);
|
||||
}
|
||||
|
||||
void py_tuple__setitem(py_Ref self, int i, const py_Ref val){
|
||||
py_setslot(self, i, val);
|
||||
}
|
||||
|
||||
int py_tuple__len(const py_Ref self){
|
||||
return self->_obj->slots;
|
||||
}
|
@ -4,6 +4,13 @@
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
py_Ref py_getreg(int i){
|
||||
return pk_current_vm->reg + i;
|
||||
}
|
||||
|
||||
void py_setreg(int i, const py_Ref val){
|
||||
pk_current_vm->reg[i] = *val;
|
||||
}
|
||||
|
||||
py_Ref py_getdict(const py_Ref self, py_Name name){
|
||||
assert(self && self->is_ptr);
|
@ -46,14 +46,6 @@ void py_newnone(py_Ref out) {
|
||||
|
||||
void py_newnull(py_Ref out) { out->type = 0; }
|
||||
|
||||
void py_newtuple(py_Ref out, int n) {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
PyObject* obj = pk_ManagedHeap__gcnew(&vm->heap, tp_tuple, n, 0);
|
||||
out->type = tp_tuple;
|
||||
out->is_ptr = true;
|
||||
out->_obj = obj;
|
||||
}
|
||||
|
||||
void py_newfunction(py_Ref out, py_CFunction f, const char* sig) {
|
||||
py_newfunction2(out, f, sig, BindType_FUNCTION, NULL, NULL);
|
||||
}
|
||||
@ -95,9 +87,9 @@ void py_pushstr(const char* val) { py_newstr(pk_current_vm->stack.sp++, val); }
|
||||
|
||||
void py_pushstrn(const char* val, int size) { py_newstrn(pk_current_vm->stack.sp++, val, size); }
|
||||
|
||||
void py_push_none() { py_newnone(pk_current_vm->stack.sp++); }
|
||||
void py_pushnone() { py_newnone(pk_current_vm->stack.sp++); }
|
||||
|
||||
void py_push_null() { py_newnull(pk_current_vm->stack.sp++); }
|
||||
void py_pushnull() { py_newnull(pk_current_vm->stack.sp++); }
|
||||
|
||||
void py_push_notimplemented() {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
|
@ -23,29 +23,26 @@ void py_finalize() {
|
||||
pk_MemoryPools__finalize();
|
||||
}
|
||||
|
||||
int py_exec(const char* source) {
|
||||
pk_SourceData_ src = pk_SourceData__rcnew(source, "main.py", EXEC_MODE, false);
|
||||
CodeObject co;
|
||||
Error* err = pk_compile(src, &co);
|
||||
PK_DECREF(src);
|
||||
if(err) abort();
|
||||
int py_exec(const char* source) { PK_UNREACHABLE(); }
|
||||
|
||||
int py_eval(const char* source, py_Ref out) {
|
||||
CodeObject co;
|
||||
pk_SourceData_ src = pk_SourceData__rcnew(source, "main.py", EVAL_MODE, false);
|
||||
Error* err = pk_compile(src, &co);
|
||||
if(err) {
|
||||
PK_DECREF(src);
|
||||
return -1;
|
||||
}
|
||||
pk_VM* vm = pk_current_vm;
|
||||
Frame* frame = Frame__new(&co, &vm->main, NULL, vm->stack.sp, vm->stack.sp, &co);
|
||||
pk_VM__push_frame(vm, frame);
|
||||
pk_FrameResult res = pk_VM__run_top_frame(vm);
|
||||
CodeObject__dtor(&co);
|
||||
PK_DECREF(src);
|
||||
if(res == RES_ERROR) return vm->last_error->type;
|
||||
if(res == RES_RETURN) return 0;
|
||||
PK_UNREACHABLE();
|
||||
}
|
||||
|
||||
int py_eval(const char* source) {
|
||||
CodeObject* co = NULL;
|
||||
pk_VM* vm = pk_current_vm;
|
||||
Frame* frame = Frame__new(co, &vm->main, NULL, vm->stack.sp, vm->stack.sp, co);
|
||||
pk_VM__push_frame(vm, frame);
|
||||
pk_FrameResult res = pk_VM__run_top_frame(vm);
|
||||
if(res == RES_ERROR) return vm->last_error->type;
|
||||
if(res == RES_RETURN) return 0;
|
||||
if(res == RES_RETURN){
|
||||
*out = vm->last_retval;
|
||||
return 0;
|
||||
}
|
||||
PK_UNREACHABLE();
|
||||
}
|
33
src2/main.c
33
src2/main.c
@ -24,19 +24,38 @@ int main(int argc, char** argv) {
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
#endif
|
||||
|
||||
if(argc != 2) goto __HELP;
|
||||
char* source = read_file(argv[1]);
|
||||
py_initialize();
|
||||
const char* source = "1, 'a'";
|
||||
|
||||
if(py_exec(source)){
|
||||
py_Ref r0 = py_getreg(0);
|
||||
if(py_eval(source, r0)){
|
||||
py_Error* err = py_getlasterror();
|
||||
py_Error__print(err);
|
||||
}else{
|
||||
// handle the result
|
||||
py_Ref _0 = py_tuple__getitem(r0, 0);
|
||||
py_Ref _1 = py_tuple__getitem(r0, 1);
|
||||
int _L0 = py_toint(_0);
|
||||
const char* _L1 = py_tostr(_1);
|
||||
printf("%d, %s\n", _L0, _L1);
|
||||
}
|
||||
|
||||
py_finalize();
|
||||
free(source);
|
||||
|
||||
__HELP:
|
||||
printf("Usage: pocketpy [filename]\n");
|
||||
return 0;
|
||||
|
||||
// if(argc != 2) goto __HELP;
|
||||
// char* source = read_file(argv[1]);
|
||||
// py_initialize();
|
||||
|
||||
// if(py_exec(source)){
|
||||
// py_Error* err = py_getlasterror();
|
||||
// py_Error__print(err);
|
||||
// }
|
||||
|
||||
// py_finalize();
|
||||
// free(source);
|
||||
|
||||
// __HELP:
|
||||
// printf("Usage: pocketpy [filename]\n");
|
||||
// return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user