Compare commits

..

No commits in common. "c9d7525ec23a8ef9a46a66a2bbb30a74fd3cb777" and "9ecfc0196ff926cb62774903659144b1c0529cbb" have entirely different histories.

16 changed files with 167 additions and 258 deletions

View File

@ -96,14 +96,13 @@ jobs:
- name: Build and Test - name: Build and Test
run: | run: |
uname -m uname -m
python -c "import struct; print(8 * struct.calcsize('P'))"
# python cmake_build.py Debug python cmake_build.py Debug
# # gdb_commands.txt # gdb_commands.txt
# echo "run" > gdb_commands.txt echo "run" > gdb_commands.txt
# echo "backtrace" >> gdb_commands.txt echo "backtrace" >> gdb_commands.txt
# echo "quit" >> gdb_commands.txt echo "quit" >> gdb_commands.txt
# gdb -batch -x gdb_commands.txt --args ./main tests/77_builtin_func_1.py gdb -batch -x gdb_commands.txt --args ./main tests/77_builtin_func_1.py
python cmake_build.py python cmake_build.py
python scripts/run_tests.py python scripts/run_tests.py

View File

@ -1,6 +1,6 @@
set -e set -e
# python prebuild.py python prebuild.py
SRC=$(find src/ -name "*.c") SRC=$(find src/ -name "*.c")

View File

@ -1,10 +1,10 @@
set -e set -e
# python prebuild.py python prebuild.py
SRC=$(find src/ -name "*.c") SRC=$(find src/ -name "*.c")
FLAGS="-std=c11 -lm -ldl -Iinclude -O0 -Wfatal-errors -g -DDEBUG -DPK_ENABLE_OS=1" FLAGS="-std=c11 -lm -ldl -I3rd/lz4 -Iinclude -O0 -Wfatal-errors -g -DDEBUG -DPK_ENABLE_OS=1 -DPK_BUILD_MODULE_LZ4"
SANITIZE_FLAGS="-fsanitize=address,leak,undefined" SANITIZE_FLAGS="-fsanitize=address,leak,undefined"
@ -13,5 +13,5 @@ if [ "$(uname)" == "Darwin" ]; then
fi fi
echo "Compiling C files..." echo "Compiling C files..."
gcc -m32 $FLAGS $SANITIZE_FLAGS $SRC src2/main.c -o main gcc -m32 $FLAGS $SANITIZE_FLAGS $SRC src2/main.c 3rd/lz4/lz4libs/lz4.c -o main

View File

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

View File

@ -8,6 +8,8 @@ MAGIC_METHOD(__ge__)
///////////////////////////// /////////////////////////////
MAGIC_METHOD(__neg__) MAGIC_METHOD(__neg__)
MAGIC_METHOD(__abs__) MAGIC_METHOD(__abs__)
MAGIC_METHOD(__float__)
MAGIC_METHOD(__int__)
MAGIC_METHOD(__round__) MAGIC_METHOD(__round__)
MAGIC_METHOD(__divmod__) MAGIC_METHOD(__divmod__)
///////////////////////////// /////////////////////////////

View File

@ -103,6 +103,15 @@ class PocketpyBindings {
late final _py_setvmctx = late final _py_setvmctx =
_py_setvmctxPtr.asFunction<void Function(ffi.Pointer<ffi.Void>)>(); _py_setvmctxPtr.asFunction<void Function(ffi.Pointer<ffi.Void>)>();
/// Interrupt the current VM and raise a `KeyboardInterrupt` exception.
void py_interrupt() {
return _py_interrupt();
}
late final _py_interruptPtr =
_lookup<ffi.NativeFunction<ffi.Void Function()>>('py_interrupt');
late final _py_interrupt = _py_interruptPtr.asFunction<void Function()>();
/// Set `sys.argv`. Used for storing command-line arguments. /// Set `sys.argv`. Used for storing command-line arguments.
void py_sys_setargv( void py_sys_setargv(
int argc, int argc,
@ -121,21 +130,6 @@ class PocketpyBindings {
late final _py_sys_setargv = _py_sys_setargvPtr late final _py_sys_setargv = _py_sys_setargvPtr
.asFunction<void Function(int, ffi.Pointer<ffi.Pointer<ffi.Char>>)>(); .asFunction<void Function(int, ffi.Pointer<ffi.Pointer<ffi.Char>>)>();
/// Set the trace function for the current VM.
void py_sys_settrace(
py_TraceFunc func,
) {
return _py_sys_settrace(
func,
);
}
late final _py_sys_settracePtr =
_lookup<ffi.NativeFunction<ffi.Void Function(py_TraceFunc)>>(
'py_sys_settrace');
late final _py_sys_settrace =
_py_sys_settracePtr.asFunction<void Function(py_TraceFunc)>();
/// Setup the callbacks for the current VM. /// Setup the callbacks for the current VM.
ffi.Pointer<py_Callbacks> py_callbacks() { ffi.Pointer<py_Callbacks> py_callbacks() {
return _py_callbacks(); return _py_callbacks();
@ -147,41 +141,6 @@ class PocketpyBindings {
late final _py_callbacks = late final _py_callbacks =
_py_callbacksPtr.asFunction<ffi.Pointer<py_Callbacks> Function()>(); _py_callbacksPtr.asFunction<ffi.Pointer<py_Callbacks> Function()>();
/// Get the current source location of the frame.
ffi.Pointer<ffi.Char> py_Frame_sourceloc(
ffi.Pointer<py_Frame> frame,
ffi.Pointer<ffi.Int> lineno,
) {
return _py_Frame_sourceloc(
frame,
lineno,
);
}
late final _py_Frame_sourcelocPtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<ffi.Char> Function(ffi.Pointer<py_Frame>,
ffi.Pointer<ffi.Int>)>>('py_Frame_sourceloc');
late final _py_Frame_sourceloc = _py_Frame_sourcelocPtr.asFunction<
ffi.Pointer<ffi.Char> Function(
ffi.Pointer<py_Frame>, ffi.Pointer<ffi.Int>)>();
/// Get the function object of the frame.
/// Returns `NULL` if not available.
py_StackRef py_Frame_function(
ffi.Pointer<py_Frame> frame,
) {
return _py_Frame_function(
frame,
);
}
late final _py_Frame_functionPtr =
_lookup<ffi.NativeFunction<py_StackRef Function(ffi.Pointer<py_Frame>)>>(
'py_Frame_function');
late final _py_Frame_function = _py_Frame_functionPtr
.asFunction<py_StackRef Function(ffi.Pointer<py_Frame>)>();
/// Run a source string. /// Run a source string.
/// @param source source string. /// @param source source string.
/// @param filename filename (for error messages). /// @param filename filename (for error messages).
@ -1515,18 +1474,6 @@ class PocketpyBindings {
late final _py_inspect_currentmodule = late final _py_inspect_currentmodule =
_py_inspect_currentmodulePtr.asFunction<py_GlobalRef Function()>(); _py_inspect_currentmodulePtr.asFunction<py_GlobalRef Function()>();
/// Get the current frame object.
/// Return `NULL` if not available.
ffi.Pointer<py_Frame> py_inspect_currentframe() {
return _py_inspect_currentframe();
}
late final _py_inspect_currentframePtr =
_lookup<ffi.NativeFunction<ffi.Pointer<py_Frame> Function()>>(
'py_inspect_currentframe');
late final _py_inspect_currentframe = _py_inspect_currentframePtr
.asFunction<ffi.Pointer<py_Frame> Function()>();
/// Bind a function to the object via "decl-based" style. /// Bind a function to the object via "decl-based" style.
/// @param obj the target object. /// @param obj the target object.
/// @param sig signature of the function. e.g. `add(x, y)`. /// @param sig signature of the function. e.g. `add(x, y)`.
@ -1881,10 +1828,9 @@ class PocketpyBindings {
_py_pushmethodPtr.asFunction<bool Function(int)>(); _py_pushmethodPtr.asFunction<bool Function(int)>();
/// Call a callable object via pocketpy's calling convention. /// Call a callable object via pocketpy's calling convention.
/// You need to prepare the stack using the following format: /// You need to prepare the stack using this form: `callable, self/nil, arg1, arg2, ..., k1, v1, k2, v2, ...`
/// `callable, self/nil, arg1, arg2, ..., k1, v1, k2, v2, ...`.
/// `argc` is the number of positional arguments excluding `self`. /// `argc` is the number of positional arguments excluding `self`.
/// `kwargc` is the number of keyword arguments. /// `kwargc` is the number of keyword arguments, i.e. the number of key-value pairs.
/// The result will be set to `py_retval()`. /// The result will be set to `py_retval()`.
/// The stack size will be reduced by `2 + argc + kwargc * 2`. /// The stack size will be reduced by `2 + argc + kwargc * 2`.
bool py_vectorcall( bool py_vectorcall(
@ -2001,7 +1947,7 @@ class PocketpyBindings {
late final _py_exception = late final _py_exception =
_py_exceptionPtr.asFunction<bool Function(int, ffi.Pointer<ffi.Char>)>(); _py_exceptionPtr.asFunction<bool Function(int, ffi.Pointer<ffi.Char>)>();
/// Raise an exception object. Always return false. /// Raise an expection object. Always return false.
bool py_raise( bool py_raise(
py_Ref arg0, py_Ref arg0,
) { ) {
@ -3067,16 +3013,6 @@ final class c11_sv extends ffi.Struct {
external int size; external int size;
} }
final class py_Frame extends ffi.Opaque {}
/// An enum for tracing events.
abstract class py_TraceEvent {
static const int TRACE_EVENT_LINE = 0;
static const int TRACE_EVENT_EXCEPTION = 1;
static const int TRACE_EVENT_PUSH = 2;
static const int TRACE_EVENT_POP = 3;
}
/// A struct contains the callbacks of the VM. /// A struct contains the callbacks of the VM.
final class py_Callbacks extends ffi.Struct { final class py_Callbacks extends ffi.Struct {
/// Used by `__import__` to load source code of a module. /// Used by `__import__` to load source code of a module.
@ -3103,12 +3039,6 @@ abstract class py_CompileMode {
static const int SINGLE_MODE = 2; static const int SINGLE_MODE = 2;
} }
typedef py_TraceFunc = ffi.Pointer<
ffi.NativeFunction<ffi.Void Function(ffi.Pointer<py_Frame>, ffi.Int32)>>;
/// A specific location in the value stack of the VM.
typedef py_StackRef = ffi.Pointer<py_TValue>;
/// A generic reference to a python object. /// A generic reference to a python object.
typedef py_Ref = ffi.Pointer<py_TValue>; typedef py_Ref = ffi.Pointer<py_TValue>;
@ -3134,6 +3064,9 @@ typedef py_ObjectRef = ffi.Pointer<py_TValue>;
typedef py_CFunction = ffi.Pointer< typedef py_CFunction = ffi.Pointer<
ffi.NativeFunction<ffi.Bool Function(ffi.Int argc, py_StackRef argv)>>; 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>;
/// An integer that represents a python identifier. This is to achieve string pooling and fast name /// An integer that represents a python identifier. This is to achieve string pooling and fast name
/// resolution. /// resolution.
typedef py_Name = ffi.Uint16; typedef py_Name = ffi.Uint16;
@ -3159,9 +3092,9 @@ typedef py_ItemRef = ffi.Pointer<py_TValue>;
/// %p: void* /// %p: void*
/// %t: py_Type /// %t: py_Type
/// %n: py_Name /// %n: py_Name
abstract class py_MagicName { abstract class py_MagicNames {
/// 0 is reserved /// 0 is reserved
static const int py_MagicName__NULL = 0; static const int py_MagicNames__NULL = 0;
/// math operators /// math operators
static const int __lt__ = 1; static const int __lt__ = 1;
@ -3172,68 +3105,70 @@ abstract class py_MagicName {
/// ////////////////////////// /// //////////////////////////
static const int __neg__ = 5; static const int __neg__ = 5;
static const int __abs__ = 6; static const int __abs__ = 6;
static const int __round__ = 7; static const int __float__ = 7;
static const int __divmod__ = 8; static const int __int__ = 8;
static const int __round__ = 9;
static const int __divmod__ = 10;
/// ////////////////////////// /// //////////////////////////
static const int __add__ = 9; static const int __add__ = 11;
static const int __radd__ = 10; static const int __radd__ = 12;
static const int __sub__ = 11; static const int __sub__ = 13;
static const int __rsub__ = 12; static const int __rsub__ = 14;
static const int __mul__ = 13; static const int __mul__ = 15;
static const int __rmul__ = 14; static const int __rmul__ = 16;
static const int __truediv__ = 15; static const int __truediv__ = 17;
static const int __rtruediv__ = 16; static const int __rtruediv__ = 18;
static const int __floordiv__ = 17; static const int __floordiv__ = 19;
static const int __rfloordiv__ = 18; static const int __rfloordiv__ = 20;
static const int __mod__ = 19; static const int __mod__ = 21;
static const int __rmod__ = 20; static const int __rmod__ = 22;
static const int __pow__ = 21; static const int __pow__ = 23;
static const int __rpow__ = 22; static const int __rpow__ = 24;
static const int __matmul__ = 23; static const int __matmul__ = 25;
static const int __lshift__ = 24; static const int __lshift__ = 26;
static const int __rshift__ = 25; static const int __rshift__ = 27;
static const int __and__ = 26; static const int __and__ = 28;
static const int __or__ = 27; static const int __or__ = 29;
static const int __xor__ = 28; static const int __xor__ = 30;
/// ////////////////////////// /// //////////////////////////
static const int __repr__ = 29; static const int __repr__ = 31;
static const int __str__ = 30; static const int __str__ = 32;
static const int __hash__ = 31; static const int __hash__ = 33;
static const int __len__ = 32; static const int __len__ = 34;
static const int __iter__ = 33; static const int __iter__ = 35;
static const int __next__ = 34; static const int __next__ = 36;
static const int __contains__ = 35; static const int __contains__ = 37;
static const int __bool__ = 36; static const int __bool__ = 38;
static const int __invert__ = 37; static const int __invert__ = 39;
/// ////////////////////////// /// //////////////////////////
static const int __eq__ = 38; static const int __eq__ = 40;
static const int __ne__ = 39; static const int __ne__ = 41;
/// indexer /// indexer
static const int __getitem__ = 40; static const int __getitem__ = 42;
static const int __setitem__ = 41; static const int __setitem__ = 43;
static const int __delitem__ = 42; static const int __delitem__ = 44;
/// specials /// specials
static const int __new__ = 43; static const int __new__ = 45;
static const int __init__ = 44; static const int __init__ = 46;
static const int __call__ = 45; static const int __call__ = 47;
static const int __enter__ = 46; static const int __enter__ = 48;
static const int __exit__ = 47; static const int __exit__ = 49;
static const int __name__ = 48; static const int __name__ = 50;
static const int __all__ = 49; static const int __all__ = 51;
static const int __package__ = 50; static const int __package__ = 52;
static const int __path__ = 51; static const int __path__ = 53;
static const int __class__ = 52; static const int __class__ = 54;
static const int __getattr__ = 53; static const int __getattr__ = 55;
static const int __reduce__ = 54; static const int __reduce__ = 56;
static const int __missing__ = 55; static const int __missing__ = 57;
} }
abstract class py_PredefinedType { abstract class py_PredefinedTypes {
static const int tp_nil = 0; static const int tp_nil = 0;
static const int tp_object = 1; static const int tp_object = 1;
@ -3299,7 +3234,7 @@ abstract class py_PredefinedType {
static const int tp_KeyboardInterrupt = 36; static const int tp_KeyboardInterrupt = 36;
static const int tp_StopIteration = 37; static const int tp_StopIteration = 37;
static const int tp_SyntaxError = 38; static const int tp_SyntaxError = 38;
static const int tp_RecursionError = 39; static const int tp_StackOverflowError = 39;
static const int tp_OSError = 40; static const int tp_OSError = 40;
static const int tp_NotImplementedError = 41; static const int tp_NotImplementedError = 41;
static const int tp_TypeError = 42; static const int tp_TypeError = 42;
@ -3329,19 +3264,19 @@ abstract class py_PredefinedType {
static const int tp_chunked_array2d = 62; static const int tp_chunked_array2d = 62;
} }
const String PK_VERSION = '2.0.7'; const String PK_VERSION = '2.0.6';
const int PK_VERSION_MAJOR = 2; const int PK_VERSION_MAJOR = 2;
const int PK_VERSION_MINOR = 0; const int PK_VERSION_MINOR = 0;
const int PK_VERSION_PATCH = 7; const int PK_VERSION_PATCH = 6;
const int PK_LOW_MEMORY_MODE = 0; const int PK_LOW_MEMORY_MODE = 0;
const int PK_ENABLE_OS = 1; const int PK_ENABLE_OS = 1;
const int PK_GC_MIN_THRESHOLD = 32768; const int PK_GC_MIN_THRESHOLD = 16384;
const int PK_VM_STACK_SIZE = 16384; const int PK_VM_STACK_SIZE = 16384;

View File

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

View File

@ -90,6 +90,11 @@ FrameResult VM__run_top_frame(VM* self) {
py_exception(tp_RecursionError, "maximum recursion depth exceeded"); py_exception(tp_RecursionError, "maximum recursion depth exceeded");
goto __ERROR; goto __ERROR;
} }
if(self->stack.sp >= self->stack.end) {
c11__abort(
"Stack overflow! Please increase PK_VM_STACK_SIZE or reduce the max recursion limit.");
}
codes = frame->co->codes.data; codes = frame->co->codes.data;
frame->ip++; frame->ip++;

View File

@ -104,7 +104,6 @@ UnwindTarget* Frame__find_unwind_target(py_Frame* self, int iblock) {
void Frame__set_unwind_target(py_Frame* self, py_TValue* sp) { void Frame__set_unwind_target(py_Frame* self, py_TValue* sp) {
int iblock = Frame__iblock(self); int iblock = Frame__iblock(self);
assert(iblock >= 0);
UnwindTarget* existing = Frame__find_unwind_target(self, iblock); UnwindTarget* existing = Frame__find_unwind_target(self, iblock);
if(existing) { if(existing) {
existing->offset = sp - self->p0; existing->offset = sp - self->p0;
@ -122,14 +121,15 @@ void Frame__gc_mark(py_Frame* self) {
int Frame__lineno(const py_Frame* self) { int Frame__lineno(const py_Frame* self) {
int ip = self->ip; int ip = self->ip;
if(ip >= 0) return c11__getitem(BytecodeEx, &self->co->codes_ex, ip).lineno; if(ip >= 0)
if(!self->is_locals_special) return self->co->start_line; return c11__getitem(BytecodeEx, &self->co->codes_ex, ip).lineno;
if(!self->is_locals_special)
return self->co->start_line;
return 0; return 0;
} }
int Frame__iblock(const py_Frame* self) { int Frame__iblock(const py_Frame* self) {
int ip = self->ip; int ip = self->ip;
if(ip < 0) return -1;
return c11__getitem(BytecodeEx, &self->co->codes_ex, ip).iblock; return c11__getitem(BytecodeEx, &self->co->codes_ex, ip).iblock;
} }

View File

@ -171,12 +171,9 @@ bool pk_loadmethod(py_StackRef self, py_Name name) {
if(name == __new__) { if(name == __new__) {
// __new__ acts like a @staticmethod // __new__ acts like a @staticmethod
if(self->type == tp_type) { if(py_istype(self, tp_type)) {
// T.__new__(...) // T.__new__(...)
type = py_totype(self); type = py_totype(self);
} else if(self->type == tp_super) {
// super(T, obj).__new__(...)
type = *(py_Type*)py_touserdata(self);
} else { } else {
// invalid usage of `__new__` // invalid usage of `__new__`
return false; return false;
@ -190,16 +187,12 @@ bool pk_loadmethod(py_StackRef self, py_Name name) {
return false; return false;
} }
py_TValue self_bak; // to avoid overlapping
// handle super() proxy // handle super() proxy
if(py_istype(self, tp_super)) { if(py_istype(self, tp_super)) {
type = *(py_Type*)py_touserdata(self); type = *(py_Type*)py_touserdata(self);
// BUG: here we modify `self` which refers to the stack directly *self = *py_getslot(self, 0);
// If `pk_loadmethod` fails, `self` will be corrupted
self_bak = *py_getslot(self, 0);
} else { } else {
type = self->type; type = self->type;
self_bak = *self;
} }
py_Ref cls_var = py_tpfindname(type, name); py_Ref cls_var = py_tpfindname(type, name);
@ -207,6 +200,8 @@ bool pk_loadmethod(py_StackRef self, py_Name name) {
switch(cls_var->type) { switch(cls_var->type) {
case tp_function: case tp_function:
case tp_nativefunc: { case tp_nativefunc: {
py_TValue self_bak = *self;
// `out` may overlap with `self`. If we assign `out`, `self` may be corrupted.
self[0] = *cls_var; self[0] = *cls_var;
self[1] = self_bak; self[1] = self_bak;
break; break;

View File

@ -283,7 +283,7 @@ static bool dict__init__(int argc, py_Ref argv) {
for(int i = 0; i < length; i++) { for(int i = 0; i < length; i++) {
py_Ref tuple = &p[i]; py_Ref tuple = &p[i];
if(!py_istuple(tuple) || py_tuple_len(tuple) != 2) { if(!py_istuple(tuple) || py_tuple_len(tuple) != 2) {
return ValueError("dict.__init__() argument must be a list of tuple-2"); return TypeError("dict.__init__() argument must be a list of tuple-2");
} }
py_Ref key = py_tuple_getitem(tuple, 0); py_Ref key = py_tuple_getitem(tuple, 0);
py_Ref val = py_tuple_getitem(tuple, 1); py_Ref val = py_tuple_getitem(tuple, 1);

View File

@ -123,7 +123,9 @@ static bool number__pow__(int argc, py_Ref argv) {
return true; return true;
} }
static py_i64 i64_abs(py_i64 x) { return x < 0 ? -x : x; } static py_i64 i64_abs(py_i64 x) {
return x < 0 ? -x : x;
}
static py_i64 cpy11__fast_floor_div(py_i64 a, py_i64 b) { static py_i64 cpy11__fast_floor_div(py_i64 a, py_i64 b) {
assert(b != 0); assert(b != 0);
@ -314,7 +316,7 @@ static bool int__new__(int argc, py_Ref argv) {
return true; return true;
} }
case tp_str: break; // leave to the next block case tp_str: break; // leave to the next block
default: return TypeError("int() argument must be a string, number or boolean"); default: return pk_callmagic(__int__, 1, argv + 1);
} }
} }
// 2+ args -> error // 2+ args -> error
@ -386,7 +388,7 @@ static bool float__new__(int argc, py_Ref argv) {
py_newfloat(py_retval(), float_out); py_newfloat(py_retval(), float_out);
return true; return true;
} }
default: return TypeError("float() argument must be a string or a real number"); default: return pk_callmagic(__float__, 1, argv + 1);
} }
} }

View File

@ -2,7 +2,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#include <string.h>
#include "pocketpy.h" #include "pocketpy.h"
@ -30,7 +29,7 @@ static void sigint_handler(int sig) { py_interrupt(); }
#endif #endif
static char* read_file(const char* path) { char* read_file(const char* path) {
FILE* file = fopen(path, "rb"); FILE* file = fopen(path, "rb");
if(file == NULL) { if(file == NULL) {
printf("Error: file not found\n"); printf("Error: file not found\n");
@ -45,27 +44,6 @@ static char* read_file(const char* path) {
return buffer; return buffer;
} }
static void tracefunc(py_Frame* frame, enum py_TraceEvent event) {
int line;
const char* filename = py_Frame_sourceloc(frame, &line);
const char* event_str;
switch(event) {
case TRACE_EVENT_LINE:
event_str = "line";
break;
case TRACE_EVENT_EXCEPTION:
event_str = "exception";
break;
case TRACE_EVENT_PUSH:
event_str = "push";
break;
case TRACE_EVENT_POP:
event_str = "pop";
break;
}
printf("\x1b[30m%s:%d, event=%s\x1b[0m\n", filename, line, event_str);
}
static char buf[2048]; static char buf[2048];
int main(int argc, char** argv) { int main(int argc, char** argv) {
@ -77,27 +55,15 @@ int main(int argc, char** argv) {
// signal(SIGINT, sigint_handler); // signal(SIGINT, sigint_handler);
#endif #endif
bool trace = false; if(argc > 2) {
const char* filename = NULL; printf("Usage: pocketpy [filename]\n");
return 0;
for(int i = 1; i < argc; i++) {
if(strcmp(argv[i], "--trace") == 0) {
trace = true;
continue;
}
if(filename == NULL) {
filename = argv[i];
continue;
}
printf("Usage: pocketpy [--trace] filename\n");
} }
py_initialize(); py_initialize();
py_sys_setargv(argc, argv); py_sys_setargv(argc, argv);
if(trace) py_sys_settrace(tracefunc); if(argc == 1) {
if(filename == NULL) {
printf("pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ") "); printf("pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ") ");
printf("[%d bit] on %s", (int)(sizeof(void*) * 8), PY_SYS_PLATFORM_STRING); printf("[%d bit] on %s", (int)(sizeof(void*) * 8), PY_SYS_PLATFORM_STRING);
#ifndef NDEBUG #ifndef NDEBUG
@ -123,9 +89,9 @@ int main(int argc, char** argv) {
} }
} }
} else { } else {
char* source = read_file(filename); char* source = read_file(argv[1]);
if(source) { if(source) {
if(!py_exec(source, filename, EXEC_MODE, NULL)) py_printexc(); if(!py_exec(source, argv[1], EXEC_MODE, NULL)) py_printexc();
free(source); free(source);
} }
} }

View File

@ -7,7 +7,7 @@ class TestSuperBase():
return self.base_attr return self.base_attr
def error(self): def error(self):
raise RuntimeError('未能拦截错误') raise Exception('未能拦截错误')
class TestSuperChild1(TestSuperBase): class TestSuperChild1(TestSuperBase):
@ -20,7 +20,7 @@ class TestSuperChild1(TestSuperBase):
def error_handling(self): def error_handling(self):
try: try:
super(TestSuperChild1, self).error() super(TestSuperChild1, self).error()
except RuntimeError: except:
pass pass
class TestSuperChild2(TestSuperBase): class TestSuperChild2(TestSuperBase):
@ -54,22 +54,18 @@ class TestSuperNoBaseMethod(TestSuperBase):
def __init__(self): def __init__(self):
super(TestSuperNoBaseMethod, self).append(1) super(TestSuperNoBaseMethod, self).append(1)
class TestSuperNoParent():
def method(self):
super(TestSuperNoParent, self).method()
try: try:
t = TestSuperNoParent().method() t = TestSuperNoParent()
print('未能拦截错误2') print('未能拦截错误')
exit(2) exit(2)
except AttributeError: except:
pass pass
try: try:
t = TestSuperNoBaseMethod() t = TestSuperNoBaseMethod()
print('未能拦截错误3') print('未能拦截错误')
exit(3) exit(3)
except AttributeError: except:
pass pass
class B(): class B():
@ -86,17 +82,17 @@ class D():
try: try:
c = C() c = C()
c.method() c.method()
print('未能拦截错误4') print('未能拦截错误')
exit(4) exit(4)
except AttributeError: except:
pass pass
try: try:
d = D() d = D()
d.method() d.method()
print('未能拦截错误5') print('未能拦截错误')
exit(5) exit(5)
except TypeError: except:
pass pass
# test hash: # test hash:
@ -137,16 +133,16 @@ assert type(hash(a)) is int
# 测试不可哈希对象 # 测试不可哈希对象
try: try:
hash({1:1}) hash({1:1})
print('未能拦截错误6') print('未能拦截错误')
exit(6) exit(6)
except TypeError: except:
pass pass
try: try:
hash([1]) hash([1])
print('未能拦截错误7') print('未能拦截错误')
exit(7) exit(7)
except TypeError: except:
pass pass
# test chr # test chr
@ -169,24 +165,24 @@ repr(A())
try: try:
range(1,2,3,4) range(1,2,3,4)
print('未能拦截错误8, 在测试 range') print('未能拦截错误, 在测试 range')
exit(8) exit(8)
except TypeError: except:
pass pass
# /************ int ************/ # /************ int ************/
try: try:
int('asad') int('asad')
print('未能拦截错误9, 在测试 int') print('未能拦截错误, 在测试 int')
exit(9) exit(9)
except ValueError: except:
pass pass
try: try:
int(123, 16) int(123, 16)
print('未能拦截错误10, 在测试 int') print('未能拦截错误, 在测试 int')
exit(10) exit(10)
except TypeError: except:
pass pass
assert type(10//11) is int assert type(10//11) is int
@ -195,16 +191,16 @@ assert type(11%2) is int
try: try:
float('asad') float('asad')
print('未能拦截错误11, 在测试 float') print('未能拦截错误, 在测试 float')
exit(11) exit(11)
except ValueError: except:
pass pass
try: try:
float([]) float([])
print('未能拦截错误12, 在测试 float') print('未能拦截错误, 在测试 float')
exit(12) exit(12)
except TypeError: except:
pass pass
# /************ str ************/ # /************ str ************/
@ -216,10 +212,10 @@ assert type(12 * '12') is str
assert type('25363546'.index('63')) is int assert type('25363546'.index('63')) is int
try: try:
'25363546'.index('err') '25363546'.index('err')
print('未能拦截错误13, 在测试 str.index') print('未能拦截错误, 在测试 str.index')
exit(13) exit(13)
except ValueError as e: except:
assert str(e) == "substring not found" pass
# 未完全测试准确性----------------------------------------------- # 未完全测试准确性-----------------------------------------------
@ -231,9 +227,9 @@ assert '25363546'.find('err') == -1
# /************ list ************/ # /************ list ************/
try: try:
list(1,2) list(1,2)
print('未能拦截错误14, 在测试 list') print('未能拦截错误, 在测试 list')
exit(14) exit(14)
except TypeError: except:
pass pass
# 未完全测试准确性---------------------------------------------- # 未完全测试准确性----------------------------------------------
@ -241,10 +237,10 @@ except TypeError:
assert type([1,2,3,4,5].index(4)) is int assert type([1,2,3,4,5].index(4)) is int
try: try:
[1,2,3,4,5].index(6) [1,2,3,4,5].index(6)
print('未能拦截错误15, 在测试 list.index') print('未能拦截错误, 在测试 list.index')
exit(15) exit(15)
except ValueError as e: except:
assert str(e) == "list.index(x): x not in list" pass
@ -252,19 +248,19 @@ except ValueError as e:
# test list.remove: # test list.remove:
try: try:
[1,2,3,4,5].remove(6) [1,2,3,4,5].remove(6)
print('未能拦截错误16, 在测试 list.remove') print('未能拦截错误, 在测试 list.remove')
exit(16) exit(16)
except ValueError as e: except:
assert str(e) == "list.remove(x): x not in list" pass
# 未完全测试准确性---------------------------------------------- # 未完全测试准确性----------------------------------------------
# test list.pop: # test list.pop:
try: try:
[1,2,3,4,5].pop(1,2,3,4) [1,2,3,4,5].pop(1,2,3,4)
print('未能拦截错误17, 在测试 list.pop') print('未能拦截错误, 在测试 list.pop')
exit(17) exit(17)
except TypeError: except:
pass pass
@ -278,9 +274,9 @@ assert type(12 * [12]) is list
# test tuple: # test tuple:
try: try:
tuple(1,2) tuple(1,2)
print('未能拦截错误18, 在测试 tuple') print('未能拦截错误, 在测试 tuple')
exit(18) exit(18)
except TypeError: except:
pass pass
assert [1,2,2,3,3,3].count(3) == 3 assert [1,2,2,3,3,3].count(3) == 3

View File

@ -70,21 +70,21 @@ try:
dict([(1, 2, 3)]) dict([(1, 2, 3)])
print('未能拦截错误, 在测试 dict') print('未能拦截错误, 在测试 dict')
exit(1) exit(1)
except ValueError: except:
pass pass
try: try:
dict([(1, 2)], 1) dict([(1, 2)], 1)
print('未能拦截错误, 在测试 dict') print('未能拦截错误, 在测试 dict')
exit(1) exit(1)
except TypeError: except:
pass pass
try: try:
hash(dict([(1,2)])) hash(dict([(1,2)]))
print('未能拦截错误, 在测试 dict.__hash__') print('未能拦截错误, 在测试 dict.__hash__')
exit(1) exit(1)
except TypeError: except:
pass pass
# test dict.__iter__ # test dict.__iter__
@ -102,7 +102,7 @@ try:
{1:2, 3:4}.get(1,1, 1) {1:2, 3:4}.get(1,1, 1)
print('未能拦截错误, 在测试 dict.get') print('未能拦截错误, 在测试 dict.get')
exit(1) exit(1)
except TypeError: except:
pass pass
# 未完全测试准确性----------------------------------------------- # 未完全测试准确性-----------------------------------------------

View File

@ -52,7 +52,13 @@ assert A()[1:2, :A()[3:4, ::-1]] == (slice(1, 2, None), slice(None, (slice(3, 4,
assert 2**2**3 == 256 assert 2**2**3 == 256
assert (2**2**3)**2 == 65536 assert (2**2**3)**2 == 65536
class Number: class Number:
def __float__(self):
return 1.0
def __int__(self):
return 2
def __divmod__(self, other): def __divmod__(self, other):
return 3, 4 return 3, 4
@ -60,6 +66,9 @@ class Number:
return args return args
assert divmod(Number(), 0) == (3, 4) assert divmod(Number(), 0) == (3, 4)
assert float(Number()) == 1.0
assert int(Number()) == 2
assert round(Number()) == tuple() assert round(Number()) == tuple()
assert round(Number(), 1) == (1,) assert round(Number(), 1) == (1,)