mirror of
https://github.com/pocketpy/pocketpy
synced 2026-05-06 10:13:37 +00:00
Compare commits
9 Commits
75830d2e18
...
985fd2aac7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
985fd2aac7 | ||
|
|
005a2725a1 | ||
|
|
d03b067666 | ||
|
|
0676b21da2 | ||
|
|
a2f16e5f1f | ||
|
|
a69cca59f4 | ||
|
|
7614bdcc4a | ||
|
|
984c0eefcc | ||
|
|
c048ec9faf |
@ -61,6 +61,12 @@ else()
|
|||||||
add_definitions(-DPK_ENABLE_THREADS=0)
|
add_definitions(-DPK_ENABLE_THREADS=0)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(PK_ENABLE_DLL)
|
||||||
|
add_definitions(-DPK_ENABLE_DLL=1)
|
||||||
|
else()
|
||||||
|
add_definitions(-DPK_ENABLE_DLL=0)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(PK_ENABLE_DETERMINISM)
|
if(PK_ENABLE_DETERMINISM)
|
||||||
add_definitions(-DPK_ENABLE_DETERMINISM=1)
|
add_definitions(-DPK_ENABLE_DETERMINISM=1)
|
||||||
else()
|
else()
|
||||||
@ -154,7 +160,7 @@ if(PK_ENABLE_THREADS)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(UNIX AND NOT APPLE)
|
if(UNIX AND NOT APPLE)
|
||||||
if(PK_ENABLE_OS)
|
if(PK_ENABLE_OS AND PK_ENABLE_DLL)
|
||||||
target_link_libraries(${PROJECT_NAME} dl)
|
target_link_libraries(${PROJECT_NAME} dl)
|
||||||
endif()
|
endif()
|
||||||
elseif(WIN32)
|
elseif(WIN32)
|
||||||
|
|||||||
@ -8,6 +8,7 @@ endif()
|
|||||||
# system features
|
# system features
|
||||||
option(PK_ENABLE_OS "" ON)
|
option(PK_ENABLE_OS "" ON)
|
||||||
option(PK_ENABLE_THREADS "" ON)
|
option(PK_ENABLE_THREADS "" ON)
|
||||||
|
option(PK_ENABLE_DLL "" ON)
|
||||||
option(PK_ENABLE_DETERMINISM "" ON)
|
option(PK_ENABLE_DETERMINISM "" ON)
|
||||||
option(PK_ENABLE_WATCHDOG "" OFF)
|
option(PK_ENABLE_WATCHDOG "" OFF)
|
||||||
option(PK_ENABLE_CUSTOM_SNAME "" OFF)
|
option(PK_ENABLE_CUSTOM_SNAME "" OFF)
|
||||||
|
|||||||
@ -1,18 +1,22 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
||||||
#define PK_VERSION "2.1.8"
|
#define PK_VERSION "2.1.9"
|
||||||
#define PK_VERSION_MAJOR 2
|
#define PK_VERSION_MAJOR 2
|
||||||
#define PK_VERSION_MINOR 1
|
#define PK_VERSION_MINOR 1
|
||||||
#define PK_VERSION_PATCH 8
|
#define PK_VERSION_PATCH 9
|
||||||
|
|
||||||
/*************** feature settings ***************/
|
/*************** feature settings ***************/
|
||||||
#ifndef PK_ENABLE_OS // can be overridden by cmake
|
#ifndef PK_ENABLE_OS // can be overridden by cmake
|
||||||
#define PK_ENABLE_OS 1
|
#define PK_ENABLE_OS 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef PK_ENABLE_THREADS // can be overridden by cmake
|
#ifndef PK_ENABLE_THREADS // must be enabled from cmake
|
||||||
#define PK_ENABLE_THREADS 1
|
#define PK_ENABLE_THREADS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PK_ENABLE_DLL // must be enabled from cmake
|
||||||
|
#define PK_ENABLE_DLL 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef PK_ENABLE_DETERMINISM // must be enabled from cmake
|
#ifndef PK_ENABLE_DETERMINISM // must be enabled from cmake
|
||||||
|
|||||||
@ -70,6 +70,7 @@ args_proxy interface<Derived>::operator* () const {
|
|||||||
template <typename Derived>
|
template <typename Derived>
|
||||||
template <return_value_policy policy, typename... Args>
|
template <return_value_policy policy, typename... Args>
|
||||||
object interface<Derived>::operator() (Args&&... args) const {
|
object interface<Derived>::operator() (Args&&... args) const {
|
||||||
|
py_StackRef p0 = py_peek(0); // checkpoint before pushing so py_clearexc can safely rewind
|
||||||
py_push(ptr());
|
py_push(ptr());
|
||||||
py_pushnil();
|
py_pushnil();
|
||||||
|
|
||||||
@ -108,7 +109,13 @@ object interface<Derived>::operator() (Args&&... args) const {
|
|||||||
|
|
||||||
(foreach(std::forward<Args>(args)), ...);
|
(foreach(std::forward<Args>(args)), ...);
|
||||||
|
|
||||||
raise_call<py_vectorcall>(argc, kwargsc);
|
if(!py_vectorcall(argc, kwargsc)) {
|
||||||
|
py_matchexc(tp_Exception);
|
||||||
|
object e = object::from_ret();
|
||||||
|
auto what = py_formatexc();
|
||||||
|
py_clearexc(p0);
|
||||||
|
throw python_error(what, std::move(e));
|
||||||
|
}
|
||||||
|
|
||||||
return object::from_ret();
|
return object::from_ret();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
#include "pybind11.h"
|
#include "pybind11.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|||||||
@ -79,3 +79,18 @@ TEST_F(PYBIND11_TEST, exception_cpp_to_python) {
|
|||||||
TEST_EXCEPTION(attribute_error, AttributeError);
|
TEST_EXCEPTION(attribute_error, AttributeError);
|
||||||
TEST_EXCEPTION(runtime_error, RuntimeError);
|
TEST_EXCEPTION(runtime_error, RuntimeError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Regression test: operator() must throw python_error instead of crashing when Python raises (#469)
|
||||||
|
TEST_F(PYBIND11_TEST, operator_call_propagates_python_error) {
|
||||||
|
py::exec("def f(x):\n raise ValueError('intentional error')");
|
||||||
|
py::object fn = py::eval("f");
|
||||||
|
|
||||||
|
bool caught = false;
|
||||||
|
try {
|
||||||
|
fn(py::int_(1));
|
||||||
|
} catch(py::python_error& e) {
|
||||||
|
caught = true;
|
||||||
|
EXPECT_TRUE(e.match(tp_ValueError));
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(caught);
|
||||||
|
}
|
||||||
|
|||||||
@ -1530,9 +1530,9 @@ class PocketpyBindings {
|
|||||||
ffi.NativeFunction<
|
ffi.NativeFunction<
|
||||||
ffi.Bool Function(py_Ref self, py_Name name)>>)>();
|
ffi.Bool Function(py_Ref self, py_Name name)>>)>();
|
||||||
|
|
||||||
/// Get the current `function` object on the stack.
|
/// Get the current `Callable` object on the stack of the most recent vectorcall.
|
||||||
/// Return `NULL` if not available.
|
/// Return `NULL` if not available.
|
||||||
/// NOTE: This function should be placed at the beginning of your decl-based bindings.
|
/// NOTE: This function should be placed at the beginning of your bindings or you will get wrong result.
|
||||||
py_StackRef py_inspect_currentfunction() {
|
py_StackRef py_inspect_currentfunction() {
|
||||||
return _py_inspect_currentfunction();
|
return _py_inspect_currentfunction();
|
||||||
}
|
}
|
||||||
@ -3635,6 +3635,22 @@ class PocketpyBindings {
|
|||||||
late final _py_newvec3i =
|
late final _py_newvec3i =
|
||||||
_py_newvec3iPtr.asFunction<void Function(py_OutRef, c11_vec3i)>();
|
_py_newvec3iPtr.asFunction<void Function(py_OutRef, c11_vec3i)>();
|
||||||
|
|
||||||
|
void py_newvec4i(
|
||||||
|
py_OutRef out,
|
||||||
|
c11_vec4i arg1,
|
||||||
|
) {
|
||||||
|
return _py_newvec4i(
|
||||||
|
out,
|
||||||
|
arg1,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _py_newvec4iPtr =
|
||||||
|
_lookup<ffi.NativeFunction<ffi.Void Function(py_OutRef, c11_vec4i)>>(
|
||||||
|
'py_newvec4i');
|
||||||
|
late final _py_newvec4i =
|
||||||
|
_py_newvec4iPtr.asFunction<void Function(py_OutRef, c11_vec4i)>();
|
||||||
|
|
||||||
void py_newcolor32(
|
void py_newcolor32(
|
||||||
py_OutRef out,
|
py_OutRef out,
|
||||||
c11_color32 arg1,
|
c11_color32 arg1,
|
||||||
@ -3715,6 +3731,19 @@ class PocketpyBindings {
|
|||||||
late final _py_tovec3i =
|
late final _py_tovec3i =
|
||||||
_py_tovec3iPtr.asFunction<c11_vec3i Function(py_Ref)>();
|
_py_tovec3iPtr.asFunction<c11_vec3i Function(py_Ref)>();
|
||||||
|
|
||||||
|
c11_vec4i py_tovec4i(
|
||||||
|
py_Ref self,
|
||||||
|
) {
|
||||||
|
return _py_tovec4i(
|
||||||
|
self,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _py_tovec4iPtr =
|
||||||
|
_lookup<ffi.NativeFunction<c11_vec4i Function(py_Ref)>>('py_tovec4i');
|
||||||
|
late final _py_tovec4i =
|
||||||
|
_py_tovec4iPtr.asFunction<c11_vec4i Function(py_Ref)>();
|
||||||
|
|
||||||
ffi.Pointer<c11_mat3x3> py_tomat3x3(
|
ffi.Pointer<c11_mat3x3> py_tomat3x3(
|
||||||
py_Ref self,
|
py_Ref self,
|
||||||
) {
|
) {
|
||||||
@ -3932,10 +3961,32 @@ final class UnnamedUnion1 extends ffi.Union {
|
|||||||
@ffi.Int64()
|
@ffi.Int64()
|
||||||
external int _i64;
|
external int _i64;
|
||||||
|
|
||||||
|
@ffi.Double()
|
||||||
|
external double _f64;
|
||||||
|
|
||||||
|
@ffi.Bool()
|
||||||
|
external bool _bool;
|
||||||
|
|
||||||
|
external py_CFunction _cfunc;
|
||||||
|
|
||||||
|
external ffi.Pointer<ffi.Void> _obj;
|
||||||
|
|
||||||
|
external ffi.Pointer<ffi.Void> _ptr;
|
||||||
|
|
||||||
@ffi.Array.multi([16])
|
@ffi.Array.multi([16])
|
||||||
external ffi.Array<ffi.Char> _chars;
|
external ffi.Array<ffi.Char> _chars;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Native function signature.
|
||||||
|
/// @param argc number of arguments.
|
||||||
|
/// @param argv array of arguments. Use `py_arg(i)` macro to get the i-th argument.
|
||||||
|
/// @return `true` if the function is successful or `false` if an exception is raised.
|
||||||
|
typedef py_CFunction = ffi.Pointer<
|
||||||
|
ffi.NativeFunction<ffi.Bool Function(ffi.Int argc, py_StackRef argv)>>;
|
||||||
|
|
||||||
|
/// A specific location in the value stack of the VM.
|
||||||
|
typedef py_StackRef = ffi.Pointer<py_TValue>;
|
||||||
|
|
||||||
/// A string view type. It is helpful for passing strings which are not null-terminated.
|
/// A string view type. It is helpful for passing strings which are not null-terminated.
|
||||||
final class c11_sv extends ffi.Struct {
|
final class c11_sv extends ffi.Struct {
|
||||||
external ffi.Pointer<ffi.Char> data;
|
external ffi.Pointer<ffi.Char> data;
|
||||||
@ -4027,22 +4078,12 @@ typedef py_TraceFunc = ffi.Pointer<
|
|||||||
/// An output reference for returning a value. Only use this for function arguments.
|
/// An output reference for returning a value. Only use this for function arguments.
|
||||||
typedef py_OutRef = ffi.Pointer<py_TValue>;
|
typedef py_OutRef = ffi.Pointer<py_TValue>;
|
||||||
|
|
||||||
/// A specific location in the value stack of the VM.
|
|
||||||
typedef py_StackRef = ffi.Pointer<py_TValue>;
|
|
||||||
|
|
||||||
/// A 64-bit integer type. Corresponds to `int` in python.
|
/// A 64-bit integer type. Corresponds to `int` in python.
|
||||||
typedef py_i64 = ffi.Int64;
|
typedef py_i64 = ffi.Int64;
|
||||||
|
|
||||||
/// A 64-bit floating-point type. Corresponds to `float` in python.
|
/// A 64-bit floating-point type. Corresponds to `float` in python.
|
||||||
typedef py_f64 = ffi.Double;
|
typedef py_f64 = ffi.Double;
|
||||||
|
|
||||||
/// Native function signature.
|
|
||||||
/// @param argc number of arguments.
|
|
||||||
/// @param argv array of arguments. Use `py_arg(i)` macro to get the i-th argument.
|
|
||||||
/// @return `true` if the function is successful or `false` if an exception is raised.
|
|
||||||
typedef py_CFunction = ffi.Pointer<
|
|
||||||
ffi.NativeFunction<ffi.Bool Function(ffi.Int argc, py_StackRef argv)>>;
|
|
||||||
|
|
||||||
/// A pointer that represents a python identifier. For fast name resolution.
|
/// A pointer that represents a python identifier. For fast name resolution.
|
||||||
typedef py_Name = ffi.Pointer<py_OpaqueName>;
|
typedef py_Name = ffi.Pointer<py_OpaqueName>;
|
||||||
|
|
||||||
@ -4125,9 +4166,30 @@ final class UnnamedStruct4 extends ffi.Struct {
|
|||||||
external int z;
|
external int z;
|
||||||
}
|
}
|
||||||
|
|
||||||
final class c11_color32 extends ffi.Union {
|
final class c11_vec4i extends ffi.Union {
|
||||||
external UnnamedStruct5 unnamed;
|
external UnnamedStruct5 unnamed;
|
||||||
|
|
||||||
|
@ffi.Array.multi([4])
|
||||||
|
external ffi.Array<ffi.Int> data;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class UnnamedStruct5 extends ffi.Struct {
|
||||||
|
@ffi.Int()
|
||||||
|
external int x;
|
||||||
|
|
||||||
|
@ffi.Int()
|
||||||
|
external int y;
|
||||||
|
|
||||||
|
@ffi.Int()
|
||||||
|
external int z;
|
||||||
|
|
||||||
|
@ffi.Int()
|
||||||
|
external int w;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class c11_color32 extends ffi.Union {
|
||||||
|
external UnnamedStruct6 unnamed;
|
||||||
|
|
||||||
@ffi.Array.multi([4])
|
@ffi.Array.multi([4])
|
||||||
external ffi.Array<ffi.UnsignedChar> data;
|
external ffi.Array<ffi.UnsignedChar> data;
|
||||||
|
|
||||||
@ -4135,7 +4197,7 @@ final class c11_color32 extends ffi.Union {
|
|||||||
external int u32;
|
external int u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
final class UnnamedStruct5 extends ffi.Struct {
|
final class UnnamedStruct6 extends ffi.Struct {
|
||||||
@ffi.UnsignedChar()
|
@ffi.UnsignedChar()
|
||||||
external int r;
|
external int r;
|
||||||
|
|
||||||
@ -4150,7 +4212,7 @@ final class UnnamedStruct5 extends ffi.Struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class c11_mat3x3 extends ffi.Union {
|
final class c11_mat3x3 extends ffi.Union {
|
||||||
external UnnamedStruct6 unnamed;
|
external UnnamedStruct7 unnamed;
|
||||||
|
|
||||||
@ffi.Array.multi([3, 3])
|
@ffi.Array.multi([3, 3])
|
||||||
external ffi.Array<ffi.Array<ffi.Float>> m;
|
external ffi.Array<ffi.Array<ffi.Float>> m;
|
||||||
@ -4159,7 +4221,7 @@ final class c11_mat3x3 extends ffi.Union {
|
|||||||
external ffi.Array<ffi.Float> data;
|
external ffi.Array<ffi.Float> data;
|
||||||
}
|
}
|
||||||
|
|
||||||
final class UnnamedStruct6 extends ffi.Struct {
|
final class UnnamedStruct7 extends ffi.Struct {
|
||||||
@ffi.Float()
|
@ffi.Float()
|
||||||
external double _11;
|
external double _11;
|
||||||
|
|
||||||
@ -4306,13 +4368,14 @@ abstract class py_PredefinedType {
|
|||||||
static const int tp_vec3 = 71;
|
static const int tp_vec3 = 71;
|
||||||
static const int tp_vec2i = 72;
|
static const int tp_vec2i = 72;
|
||||||
static const int tp_vec3i = 73;
|
static const int tp_vec3i = 73;
|
||||||
static const int tp_mat3x3 = 74;
|
static const int tp_vec4i = 74;
|
||||||
static const int tp_color32 = 75;
|
static const int tp_mat3x3 = 75;
|
||||||
|
static const int tp_color32 = 76;
|
||||||
|
|
||||||
/// array2d
|
/// array2d
|
||||||
static const int tp_array2d_like = 76;
|
static const int tp_array2d_like = 77;
|
||||||
static const int tp_array2d_like_iterator = 77;
|
static const int tp_array2d_like_iterator = 78;
|
||||||
static const int tp_array2d = 78;
|
static const int tp_array2d = 79;
|
||||||
static const int tp_array2d_view = 79;
|
static const int tp_array2d_view = 80;
|
||||||
static const int tp_chunked_array2d = 80;
|
static const int tp_chunked_array2d = 81;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -134,10 +134,10 @@ def atan(z: complex):
|
|||||||
return 1j / 2 * log((1 - 1j * z) / (1 + 1j * z))
|
return 1j / 2 * log((1 - 1j * z) / (1 + 1j * z))
|
||||||
|
|
||||||
def cos(z: complex):
|
def cos(z: complex):
|
||||||
return (exp(z) + exp(-z)) / 2
|
return (exp(1j * z) + exp(-1j * z)) / 2
|
||||||
|
|
||||||
def sin(z: complex):
|
def sin(z: complex):
|
||||||
return (exp(z) - exp(-z)) / (2 * 1j)
|
return (exp(1j * z) - exp(-1j * z)) / (2 * 1j)
|
||||||
|
|
||||||
def tan(z: complex):
|
def tan(z: complex):
|
||||||
return sin(z) / cos(z)
|
return sin(z) / cos(z)
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -2801,6 +2801,8 @@ static Error* compile_stmt(Compiler* self) {
|
|||||||
case TK_WITH: {
|
case TK_WITH: {
|
||||||
check(EXPR(self)); // [ <expr> ]
|
check(EXPR(self)); // [ <expr> ]
|
||||||
Ctx__s_emit_top(ctx());
|
Ctx__s_emit_top(ctx());
|
||||||
|
// Save context manager for later __exit__ call
|
||||||
|
Ctx__emit_(ctx(), OP_DUP_TOP, BC_NOARG, prev()->line);
|
||||||
Ctx__enter_block(ctx(), CodeBlockType_WITH);
|
Ctx__enter_block(ctx(), CodeBlockType_WITH);
|
||||||
NameExpr* as_name = NULL;
|
NameExpr* as_name = NULL;
|
||||||
if(match(TK_AS)) {
|
if(match(TK_AS)) {
|
||||||
@ -2809,17 +2811,33 @@ static Error* compile_stmt(Compiler* self) {
|
|||||||
as_name = NameExpr__new(prev()->line, name, name_scope(self));
|
as_name = NameExpr__new(prev()->line, name, name_scope(self));
|
||||||
}
|
}
|
||||||
Ctx__emit_(ctx(), OP_WITH_ENTER, BC_NOARG, prev()->line);
|
Ctx__emit_(ctx(), OP_WITH_ENTER, BC_NOARG, prev()->line);
|
||||||
// [ <expr> <expr>.__enter__() ]
|
|
||||||
if(as_name) {
|
if(as_name) {
|
||||||
bool ok = vtemit_store((Expr*)as_name, ctx());
|
bool ok = vtemit_store((Expr*)as_name, ctx());
|
||||||
vtdelete((Expr*)as_name);
|
vtdelete((Expr*)as_name);
|
||||||
if(!ok) return SyntaxError(self, "invalid syntax");
|
if(!ok) return SyntaxError(self, "invalid syntax");
|
||||||
} else {
|
} else {
|
||||||
// discard `__enter__()`'s return value
|
|
||||||
Ctx__emit_(ctx(), OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
|
Ctx__emit_(ctx(), OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
|
||||||
}
|
}
|
||||||
|
// Wrap body in try-except to ensure __exit__ is called even on exception
|
||||||
|
Ctx__enter_block(ctx(), CodeBlockType_TRY);
|
||||||
|
Ctx__emit_(ctx(), OP_BEGIN_TRY, BC_NOARG, prev()->line);
|
||||||
check(compile_block_body(self));
|
check(compile_block_body(self));
|
||||||
|
Ctx__emit_(ctx(), OP_END_TRY, BC_NOARG, BC_KEEPLINE);
|
||||||
|
// Normal exit: call __exit__(None, None, None)
|
||||||
|
Ctx__emit_(ctx(), OP_LOAD_NONE, BC_NOARG, prev()->line);
|
||||||
|
Ctx__emit_(ctx(), OP_LOAD_NONE, BC_NOARG, prev()->line);
|
||||||
|
Ctx__emit_(ctx(), OP_LOAD_NONE, BC_NOARG, prev()->line);
|
||||||
Ctx__emit_(ctx(), OP_WITH_EXIT, BC_NOARG, prev()->line);
|
Ctx__emit_(ctx(), OP_WITH_EXIT, BC_NOARG, prev()->line);
|
||||||
|
int jump_patch = Ctx__emit_(ctx(), OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE);
|
||||||
|
Ctx__exit_block(ctx());
|
||||||
|
// Exception handler: call __exit__ with exception info, then re-raise
|
||||||
|
Ctx__emit_(ctx(), OP_PUSH_EXCEPTION, BC_NOARG, BC_KEEPLINE);
|
||||||
|
Ctx__emit_(ctx(), OP_LOAD_NONE, BC_NOARG, BC_KEEPLINE); // exc_type
|
||||||
|
Ctx__emit_(ctx(), OP_ROT_TWO, BC_NOARG, BC_KEEPLINE); // reorder: [cm, None, exc]
|
||||||
|
Ctx__emit_(ctx(), OP_LOAD_NONE, BC_NOARG, BC_KEEPLINE); // exc_tb
|
||||||
|
Ctx__emit_(ctx(), OP_WITH_EXIT, BC_NOARG, prev()->line);
|
||||||
|
Ctx__emit_(ctx(), OP_RE_RAISE, BC_NOARG, BC_KEEPLINE);
|
||||||
|
Ctx__patch_jump(ctx(), jump_patch);
|
||||||
Ctx__exit_block(ctx());
|
Ctx__exit_block(ctx());
|
||||||
} break;
|
} break;
|
||||||
/*************************************************/
|
/*************************************************/
|
||||||
|
|||||||
@ -1122,14 +1122,35 @@ __NEXT_STEP:
|
|||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
case OP_WITH_EXIT: {
|
case OP_WITH_EXIT: {
|
||||||
// [expr]
|
// Stack: [cm, exc_type, exc_val, exc_tb]
|
||||||
py_push(TOP());
|
// Call cm.__exit__(exc_type, exc_val, exc_tb)
|
||||||
|
py_Ref exc_tb = TOP();
|
||||||
|
py_Ref exc_val = SECOND();
|
||||||
|
py_Ref exc_type = THIRD();
|
||||||
|
py_Ref cm = FOURTH();
|
||||||
|
|
||||||
|
// Save all values from stack
|
||||||
|
py_TValue saved_cm = *cm;
|
||||||
|
py_TValue saved_exc_type = *exc_type;
|
||||||
|
py_TValue saved_exc_val = *exc_val;
|
||||||
|
py_TValue saved_exc_tb = *exc_tb;
|
||||||
|
self->stack.sp -= 4;
|
||||||
|
|
||||||
|
// Push cm and get __exit__ method
|
||||||
|
py_push(&saved_cm);
|
||||||
if(!py_pushmethod(__exit__)) {
|
if(!py_pushmethod(__exit__)) {
|
||||||
TypeError("'%t' object does not support the context manager protocol", TOP()->type);
|
TypeError("'%t' object does not support the context manager protocol", saved_cm.type);
|
||||||
goto __ERROR;
|
goto __ERROR;
|
||||||
}
|
}
|
||||||
if(!py_vectorcall(0, 0)) goto __ERROR;
|
|
||||||
POP();
|
// Push arguments: exc_type, exc_val, exc_tb
|
||||||
|
PUSH(&saved_exc_type);
|
||||||
|
PUSH(&saved_exc_val);
|
||||||
|
PUSH(&saved_exc_tb);
|
||||||
|
|
||||||
|
// Call __exit__(exc_type, exc_val, exc_tb)
|
||||||
|
if(!py_vectorcall(3, 0)) goto __ERROR;
|
||||||
|
py_pop(); // discard return value
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
///////////
|
///////////
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#include "pocketpy/pocketpy.h"
|
#include "pocketpy/pocketpy.h"
|
||||||
|
|
||||||
#if PK_IS_DESKTOP_PLATFORM && PK_ENABLE_OS
|
#if PK_IS_DESKTOP_PLATFORM && PK_ENABLE_OS && PK_ENABLE_DLL
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef bool (*py_module_initialize_t)() PY_RAISE PY_RETURN;
|
typedef bool (*py_module_initialize_t)() PY_RAISE PY_RETURN;
|
||||||
@ -21,14 +23,44 @@ int load_module_from_dll_desktop_only(const char* path) PY_RAISE PY_RETURN {
|
|||||||
if(dll == NULL) return 0;
|
if(dll == NULL) return 0;
|
||||||
py_module_initialize_t f_init = (py_module_initialize_t)GetProcAddress(dll, f_init_name);
|
py_module_initialize_t f_init = (py_module_initialize_t)GetProcAddress(dll, f_init_name);
|
||||||
#else
|
#else
|
||||||
void* dll = dlopen(path, RTLD_LAZY);
|
void* dll = NULL;
|
||||||
|
// On Linux, dlopen doesn't automatically add .so suffix like Windows does with .dll
|
||||||
|
// Also, CMake typically generates libXxx.so instead of Xxx.so
|
||||||
|
// Try: path.so, libpath.so, then the original path
|
||||||
|
char* path_with_so = NULL;
|
||||||
|
char* path_with_lib = NULL;
|
||||||
|
size_t path_len = strlen(path);
|
||||||
|
|
||||||
|
// Try path.so
|
||||||
|
path_with_so = py_malloc(path_len + 4); // .so + null terminator
|
||||||
|
if(path_with_so != NULL) {
|
||||||
|
strcpy(path_with_so, path);
|
||||||
|
strcat(path_with_so, ".so");
|
||||||
|
dll = dlopen(path_with_so, RTLD_LAZY);
|
||||||
|
py_free(path_with_so);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try libpath.so if path.so didn't work
|
||||||
|
if(dll == NULL) {
|
||||||
|
path_with_lib = py_malloc(path_len + 7); // lib + .so + null terminator
|
||||||
|
if(path_with_lib != NULL) {
|
||||||
|
strcpy(path_with_lib, "lib");
|
||||||
|
strcat(path_with_lib, path);
|
||||||
|
strcat(path_with_lib, ".so");
|
||||||
|
dll = dlopen(path_with_lib, RTLD_LAZY);
|
||||||
|
py_free(path_with_lib);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to original path
|
||||||
|
if(dll == NULL) {
|
||||||
|
dll = dlopen(path, RTLD_LAZY);
|
||||||
|
}
|
||||||
|
|
||||||
if(dll == NULL) return 0;
|
if(dll == NULL) return 0;
|
||||||
py_module_initialize_t f_init = (py_module_initialize_t)dlsym(dll, f_init_name);
|
py_module_initialize_t f_init = (py_module_initialize_t)dlsym(dll, f_init_name);
|
||||||
#endif
|
#endif
|
||||||
if(f_init == NULL) {
|
if(f_init == NULL) return 0;
|
||||||
RuntimeError("%s() not found in '%s'", f_init_name, path);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
bool success = f_init();
|
bool success = f_init();
|
||||||
if(!success) return -1;
|
if(!success) return -1;
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@ -27,4 +27,29 @@ assert path == ['enter', 'in', 'exit']
|
|||||||
|
|
||||||
path.clear()
|
path.clear()
|
||||||
|
|
||||||
|
# Test that __exit__ is called even when an exception occurs
|
||||||
|
class B:
|
||||||
|
def __init__(self):
|
||||||
|
self.path = []
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
path.append('enter')
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
|
path.append('exit')
|
||||||
|
if exc_type is not None:
|
||||||
|
path.append('exception')
|
||||||
|
return False # propagate exception
|
||||||
|
|
||||||
|
try:
|
||||||
|
with B():
|
||||||
|
path.append('before_raise')
|
||||||
|
raise ValueError('test')
|
||||||
|
path.append('after_raise') # should not be reached
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
assert path == ['enter', 'before_raise', 'exit', 'exception'], f"Expected ['enter', 'before_raise', 'exit', 'exception'], got {path}"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user