Compare commits

...

3 Commits

Author SHA1 Message Date
blueloveTH
2161532677 fix 2026-07-22 13:21:26 +08:00
blueloveTH
beb1557d00 bump to v2.2.0 2026-07-22 12:49:00 +08:00
BLUELOVETH
4e2b40db2d
test fastpath for self.* read (#535)
* test fastpath for `self.*` read

* bak
2026-07-22 12:36:58 +08:00
13 changed files with 102 additions and 23 deletions

View File

@ -195,6 +195,7 @@ And these are the results of the primes benchmark on Intel i5-12400F, WSL (Ubunt
| | Description |
|-----------------------------------------------------------------|--------------------------------------------------------------------------|
| [Tesselmax.EM](https://fdtd.io) | Distributed electromagnetic field simulator for silicon photonics and RF/interconnect design. |
| [godot-pocketpy](https://github.com/pocketpy/godot-pocketpy) | Godot extension for using pocketpy in Godot Engine. |
| [TIC-80](https://github.com/nesbox/TIC-80) | TIC-80 is a fantasy computer for making, playing and sharing tiny games. |
| [py-js](https://github.com/shakfu/py-js) | Python3 externals for Max / MSP. |
@ -215,7 +216,7 @@ All kinds of contributions are welcome. Please read [CONTRIBUTING.md](CONTRIBUTI
- any suggestions
- any questions
If you find pkpy useful, consider star this repository (●'◡'●)
If you find pkpy useful, consider star this repository.
## Sponsor this project
@ -226,6 +227,17 @@ You can sponsor this project via these ways.
Your sponsorship will help us develop pkpy continuously.
## Premium supporter
Special thanks to our premium supporter, Tesselmax, for sponsoring the development of pocketpy.
Tesselmax builds Tesselmax.EM, a distributed electromagnetic field simulator for silicon
photonics and RF/interconnect design (FDTD, FDFD, and mode solving across GPU clusters).
Tesselmax embeds pocketpy as the scripting engine in our simulation console, so user scripts drive
geometry, materials, sources, and post-processing.
Website: [https://fdtd.io](https://fdtd.io)
## Reference
+ [cpython](https://github.com/python/cpython)

View File

@ -51,7 +51,7 @@ On Windows platform, only MSVC compiler is officially supported.
## Star the repo
If you find pkpy useful, consider [star this repository](https://github.com/blueloveth/pocketpy) (●'◡'●)
If you find pkpy useful, consider [star this repository](https://github.com/blueloveth/pocketpy).
## Sponsor this project
@ -62,6 +62,17 @@ You can sponsor this project via these ways.
Your sponsorship will help us develop pkpy continuously.
## Premium supporter
Special thanks to our premium supporter, Tesselmax, for sponsoring the development of pocketpy.
Tesselmax builds Tesselmax.EM, a distributed electromagnetic field simulator for silicon
photonics and RF/interconnect design (FDTD, FDFD, and mode solving across GPU clusters).
Tesselmax embeds pocketpy as the scripting engine in our simulation console, so user scripts drive
geometry, materials, sources, and post-processing.
Website: [https://fdtd.io](https://fdtd.io)
## Upgrade to v2.0
pkpy v2.0 is a C11 project instead of C++17. All your existing code for v1.x won't work anymore.

View File

@ -3,7 +3,7 @@ output: .retype
url: https://pocketpy.dev
branding:
title: pocketpy
label: v2.1.9
label: v2.2.0
logo: "./static/logo.png"
favicon: "./static/logo.png"
meta:

View File

@ -1,10 +1,10 @@
#pragma once
// clang-format off
#define PK_VERSION "2.1.9"
#define PK_VERSION "2.2.0"
#define PK_VERSION_MAJOR 2
#define PK_VERSION_MINOR 1
#define PK_VERSION_PATCH 9
#define PK_VERSION_MINOR 2
#define PK_VERSION_PATCH 0
/*************** feature settings ***************/
#ifndef PK_ENABLE_OS // can be overridden by cmake

View File

@ -27,6 +27,7 @@ OPCODE(LOAD_NAME)
OPCODE(LOAD_NONLOCAL)
OPCODE(LOAD_GLOBAL)
OPCODE(LOAD_ATTR)
OPCODE(LOAD_SELF_ATTR)
OPCODE(LOAD_CLASS_GLOBAL)
OPCODE(LOAD_METHOD)
OPCODE(LOAD_SUBSCR)
@ -35,6 +36,7 @@ OPCODE(STORE_FAST)
OPCODE(STORE_NAME)
OPCODE(STORE_GLOBAL)
OPCODE(STORE_ATTR)
OPCODE(STORE_SELF_ATTR)
OPCODE(STORE_SUBSCR)
OPCODE(DELETE_FAST)

View File

@ -35,7 +35,7 @@ A new Flutter FFI plugin project.
s.prepare_command = <<-CMD
rm -rf pocketpy
git clone --branch v2.1.9 --depth 1 https://github.com/pocketpy/pocketpy.git
git clone --branch v2.2.0 --depth 1 https://github.com/pocketpy/pocketpy.git
cd pocketpy
git submodule update --init --recursive --depth 1
bash build_ios_libs.sh

View File

@ -32,7 +32,7 @@ A new Flutter FFI plugin project.
s.prepare_command = <<-CMD
rm -rf pocketpy
git clone --branch v2.1.9 --depth 1 https://github.com/pocketpy/pocketpy.git
git clone --branch v2.2.0 --depth 1 https://github.com/pocketpy/pocketpy.git
cd pocketpy
git submodule update --init --recursive --depth 1
bash build_darwin_libs.sh

View File

@ -1,6 +1,6 @@
name: pocketpy
description: A lightweight Python interpreter for game engines. It supports Android/iOS/Windows/Linux/MacOS.
version: 2.1.9
version: 2.2.0
homepage: https://pocketpy.dev
repository: https://github.com/pocketpy/pocketpy

View File

@ -20,7 +20,7 @@ set(PK_BUILD_SHARED_LIB ON CACHE BOOL "" FORCE)
FetchContent_Declare(
pocketpy
GIT_REPOSITORY https://github.com/pocketpy/pocketpy.git
GIT_TAG v2.1.9
GIT_TAG v2.2.0
)
FetchContent_MakeAvailable(pocketpy)

View File

@ -60,6 +60,7 @@ typedef struct Expr {
typedef struct Ctx {
CodeObject* co; // 1 CodeEmitContext <=> 1 CodeObject*
FuncDecl* func; // optional, weakref
py_Name n_self;
int level;
int curr_iblock;
bool is_compiling_class;
@ -70,7 +71,7 @@ typedef struct Ctx {
typedef struct Expr Expr;
static void Ctx__ctor(Ctx* self, CodeObject* co, FuncDecl* func, int level);
static void Ctx__ctor(Ctx* self, CodeObject* co, FuncDecl* func, int level, py_Name n_self);
static void Ctx__dtor(Ctx* self);
static int Ctx__prepare_loop_divert(Ctx* self, int line, bool is_break);
static int Ctx__enter_block(Ctx* self, CodeBlockType type);
@ -732,9 +733,9 @@ static void NamedExpr__dtor(Expr* self_) {
static void NamedExpr__emit_(Expr* self_, Ctx* ctx) {
NamedExpr* self = (NamedExpr*)self_;
vtemit_(self->rhs, ctx); // [value]
Ctx__emit_(ctx, OP_DUP_TOP, BC_NOARG, self->line); // [value, value]
vtemit_store((Expr*)self->name, ctx); // [value]
vtemit_(self->rhs, ctx); // [value]
Ctx__emit_(ctx, OP_DUP_TOP, BC_NOARG, self->line); // [value, value]
vtemit_store((Expr*)self->name, ctx); // [value]
}
static NamedExpr* NamedExpr__new(int line, NameExpr* name, Expr* rhs) {
@ -997,8 +998,23 @@ void AttribExpr__dtor(Expr* self_) {
vtdelete(self->child);
}
static bool is_self_xxx(Expr* child, Ctx* ctx) {
if(child->vt->is_name) {
NameExpr* ne = (NameExpr*)child;
if(ne->scope == NAME_LOCAL && ne->name == ctx->n_self) {
int index = c11_smallmap_n2d__get(&ctx->co->varnames_inv, ne->name, -1);
if(index == 0) return true;
}
}
return false;
}
void AttribExpr__emit_(Expr* self_, Ctx* ctx) {
AttribExpr* self = (AttribExpr*)self_;
if(is_self_xxx(self->child, ctx)) {
Ctx__emit_(ctx, OP_LOAD_SELF_ATTR, Ctx__add_name(ctx, self->name), self->line);
return;
}
vtemit_(self->child, ctx);
Ctx__emit_(ctx, OP_LOAD_ATTR, Ctx__add_name(ctx, self->name), self->line);
}
@ -1012,6 +1028,10 @@ bool AttribExpr__emit_del(Expr* self_, Ctx* ctx) {
bool AttribExpr__emit_store(Expr* self_, Ctx* ctx) {
AttribExpr* self = (AttribExpr*)self_;
if(is_self_xxx(self->child, ctx)) {
Ctx__emit_(ctx, OP_STORE_SELF_ATTR, Ctx__add_name(ctx, self->name), self->line);
return true;
}
vtemit_(self->child, ctx);
Ctx__emit_(ctx, OP_STORE_ATTR, Ctx__add_name(ctx, self->name), self->line);
return true;
@ -1127,9 +1147,10 @@ CallExpr* CallExpr__new(int line, Expr* callable) {
}
/* context.c */
static void Ctx__ctor(Ctx* self, CodeObject* co, FuncDecl* func, int level) {
static void Ctx__ctor(Ctx* self, CodeObject* co, FuncDecl* func, int level, py_Name n_self) {
self->co = co;
self->func = func;
self->n_self = n_self;
self->level = level;
self->curr_iblock = 0;
self->is_compiling_class = false;
@ -1361,6 +1382,7 @@ typedef struct Compiler {
Token* tokens;
int tokens_length;
py_Name n_self;
int i; // current token index
c11_vector /*T=CodeEmitContext*/ contexts;
@ -1370,6 +1392,7 @@ static void Compiler__ctor(Compiler* self, SourceData_ src, Token* tokens, int t
self->src = src;
self->tokens = tokens;
self->tokens_length = tokens_length;
self->n_self = py_name("self");
self->i = 0;
c11_vector__ctor(&self->contexts, sizeof(Ctx));
}
@ -1540,7 +1563,7 @@ static Error* EXPR_VARS(Compiler* self) {
static void push_global_context(Compiler* self, CodeObject* co) {
co->start_line = self->i == 0 ? 1 : prev()->line;
Ctx* ctx = c11_vector__emplace(&self->contexts);
Ctx__ctor(ctx, co, NULL, self->contexts.length);
Ctx__ctor(ctx, co, NULL, self->contexts.length, self->n_self);
}
static Error* pop_context(Compiler* self) {
@ -1715,9 +1738,7 @@ static Error* exprWalrus(Compiler* self) {
int line = prev()->line;
// LHS is on the stack; verify it's a simple name
Expr* lhs = Ctx__s_top(ctx());
if(!lhs->vt->is_name) {
return SyntaxError(self, "':=' target must be a simple name");
}
if(!lhs->vt->is_name) { return SyntaxError(self, "':=' target must be a simple name"); }
check(parse_expression(self, PREC_NAMED_EXPR + 1, false));
Expr* rhs = Ctx__s_popx(ctx());
NameExpr* name = (NameExpr*)Ctx__s_popx(ctx());
@ -1940,7 +1961,7 @@ static Error* exprCall(Compiler* self) {
Error* err;
Expr* callable = Ctx__s_popx(ctx());
int line = prev()->line;
CallExpr* e = CallExpr__new(line, callable);
Ctx__s_push(ctx(), (Expr*)e); // push onto the stack in advance
do {
@ -2289,7 +2310,7 @@ static FuncDecl_ push_f_context(Compiler* self, c11_sv name, int* out_index) {
*out_index = top_ctx->co->func_decls.length - 1;
// push new context
top_ctx = c11_vector__emplace(&self->contexts);
Ctx__ctor(top_ctx, &decl->code, decl, self->contexts.length);
Ctx__ctor(top_ctx, &decl->code, decl, self->contexts.length, self->n_self);
return decl;
}

View File

@ -325,6 +325,23 @@ __NEXT_STEP:
}
DISPATCH();
}
case OP_LOAD_SELF_ATTR: {
assert(!frame->is_locals_special);
py_Ref val = &frame->locals[0];
if(!py_isnil(val)) {
// LOAD_ATTR
py_Name name = co_names[byte.arg];
if(py_getattr(val, name)) {
PUSH(py_retval());
} else {
goto __ERROR;
}
DISPATCH();
}
py_Name name = c11__getitem(py_Name, &frame->co->varnames, byte.arg);
UnboundLocalError(name);
goto __ERROR;
}
case OP_LOAD_CLASS_GLOBAL: {
assert(self->curr_class);
py_Name name = co_names[byte.arg];
@ -427,6 +444,20 @@ __NEXT_STEP:
STACK_SHRINK(2);
DISPATCH();
}
case OP_STORE_SELF_ATTR: {
assert(!frame->is_locals_special);
py_Ref val = &frame->locals[0];
if(!py_isnil(val)) {
// [val, a] -> a.b = val
py_Name name = co_names[byte.arg];
if(!py_setattr(val, name, TOP())) goto __ERROR;
POP();
DISPATCH();
}
py_Name name = c11__getitem(py_Name, &frame->co->varnames, byte.arg);
UnboundLocalError(name);
goto __ERROR;
}
case OP_STORE_SUBSCR: {
// [val, a, b] -> a[b] = val
py_Ref magic = py_tpfindmagic(SECOND()->type, __setitem__);

View File

@ -77,8 +77,10 @@ static bool disassemble(CodeObject* co) {
case OP_LOAD_NONLOCAL:
case OP_STORE_GLOBAL:
case OP_LOAD_ATTR:
case OP_LOAD_SELF_ATTR:
case OP_LOAD_METHOD:
case OP_STORE_ATTR:
case OP_STORE_SELF_ATTR:
case OP_DELETE_ATTR:
case OP_BEGIN_CLASS:
case OP_DELETE_GLOBAL:

View File

@ -5,8 +5,8 @@
// Magic number for CodeObject serialization: "CO" = 0x434F
#define CODEOBJECT_MAGIC 0x434F
#define CODEOBJECT_VER_MAJOR 1
#define CODEOBJECT_VER_MINOR 0
#define CODEOBJECT_VER_MINOR_MIN 0
#define CODEOBJECT_VER_MINOR 1
#define CODEOBJECT_VER_MINOR_MIN 1
// Forward declarations
static void FuncDecl__serialize(c11_serializer* s,