mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
Merge branch 'main' into main
This commit is contained in:
commit
32874a96e5
@ -5,19 +5,14 @@ project(pocketpy)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
||||
# use UNITY_BUILD if CMake version >= 3.16
|
||||
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16")
|
||||
option(PK_BUILD_WITH_UNITY "" TRUE)
|
||||
else()
|
||||
option(PK_BUILD_WITH_UNITY "" FALSE)
|
||||
endif()
|
||||
include(CMakeOptions.txt)
|
||||
|
||||
if(WIN32)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /utf-8 /jumptablerdata /GS-")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /utf-8 /jumptablerdata")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /experimental:c11atomics")
|
||||
add_compile_options(/wd4267 /wd4244)
|
||||
|
||||
@ -25,6 +20,10 @@ if(MSVC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Ox")
|
||||
add_definitions(-DNDEBUG)
|
||||
endif()
|
||||
|
||||
if(PK_ENABLE_DETERMINISM)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Oi-")
|
||||
endif()
|
||||
else()
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
|
||||
@ -35,12 +34,16 @@ else()
|
||||
if(APPLE)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-shorten-64-to-32")
|
||||
endif()
|
||||
|
||||
if(PK_ENABLE_DETERMINISM)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fexcess-precision=standard -ffp-contract=off")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_CURRENT_LIST_DIR}/include)
|
||||
file(GLOB_RECURSE POCKETPY_SRC ${CMAKE_CURRENT_LIST_DIR}/src/*.c)
|
||||
|
||||
option(PK_ENABLE_OS "" OFF)
|
||||
|
||||
if(PK_ENABLE_OS)
|
||||
add_definitions(-DPK_ENABLE_OS=1)
|
||||
endif()
|
||||
@ -55,6 +58,10 @@ if(PK_ENABLE_DETERMINISTIC_FLOAT)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(PK_ENABLE_WATCHDOG)
|
||||
add_definitions(-DPK_ENABLE_WATCHDOG=1)
|
||||
endif()
|
||||
|
||||
option(PK_BUILD_MODULE_LZ4 "" OFF)
|
||||
if(PK_BUILD_MODULE_LZ4)
|
||||
add_subdirectory(3rd/lz4)
|
||||
@ -62,27 +69,12 @@ if(PK_BUILD_MODULE_LZ4)
|
||||
add_definitions(-DPK_BUILD_MODULE_LZ4)
|
||||
endif()
|
||||
|
||||
option(PK_BUILD_MODULE_LIBHV "" OFF)
|
||||
if(PK_BUILD_MODULE_LIBHV)
|
||||
add_subdirectory(3rd/libhv)
|
||||
include_directories(3rd/libhv/include)
|
||||
add_definitions(-DPK_BUILD_MODULE_LIBHV)
|
||||
endif()
|
||||
|
||||
# PK_IS_MAIN determines whether the project is being used from root
|
||||
# or if it is added as a dependency (through add_subdirectory for example).
|
||||
if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
set(PK_IS_MAIN TRUE)
|
||||
option(PK_BUILD_SHARED_LIB "Build shared library" OFF)
|
||||
option(PK_BUILD_STATIC_LIB "Build static library" OFF)
|
||||
else()
|
||||
set(PK_IS_MAIN FALSE)
|
||||
option(PK_BUILD_SHARED_LIB "Build shared library" OFF)
|
||||
option(PK_BUILD_STATIC_LIB "Build static library" ON)
|
||||
endif()
|
||||
|
||||
option(PK_BUILD_STATIC_MAIN "Build static main" OFF)
|
||||
|
||||
if(PK_BUILD_SHARED_LIB)
|
||||
message(">> Building shared library")
|
||||
add_library(${PROJECT_NAME} SHARED ${POCKETPY_SRC})
|
||||
@ -102,7 +94,11 @@ else()
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
if(NOT PK_ENABLE_DETERMINISM)
|
||||
# use platform libm
|
||||
target_link_libraries(${PROJECT_NAME} m)
|
||||
endif()
|
||||
|
||||
if(PK_ENABLE_OS)
|
||||
target_link_libraries(${PROJECT_NAME} dl)
|
||||
endif()
|
||||
|
30
CMakeOptions.txt
Normal file
30
CMakeOptions.txt
Normal file
@ -0,0 +1,30 @@
|
||||
# use UNITY_BUILD if CMake version >= 3.16
|
||||
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16")
|
||||
option(PK_BUILD_WITH_UNITY "" TRUE)
|
||||
else()
|
||||
option(PK_BUILD_WITH_UNITY "" FALSE)
|
||||
endif()
|
||||
|
||||
# system features
|
||||
option(PK_ENABLE_OS "" OFF)
|
||||
option(PK_ENABLE_DETERMINISM "" FALSE)
|
||||
option(PK_ENABLE_WATCHDOG "" OFF)
|
||||
|
||||
# modules
|
||||
option(PK_BUILD_MODULE_LZ4 "" OFF)
|
||||
option(PK_BUILD_MODULE_LIBHV "" OFF)
|
||||
|
||||
|
||||
# PK_IS_MAIN determines whether the project is being used from root
|
||||
# or if it is added as a dependency (through add_subdirectory for example).
|
||||
if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
set(PK_IS_MAIN TRUE)
|
||||
option(PK_BUILD_SHARED_LIB "Build shared library" OFF)
|
||||
option(PK_BUILD_STATIC_LIB "Build static library" OFF)
|
||||
else()
|
||||
set(PK_IS_MAIN FALSE)
|
||||
option(PK_BUILD_SHARED_LIB "Build shared library" OFF)
|
||||
option(PK_BUILD_STATIC_LIB "Build static library" ON)
|
||||
endif()
|
||||
|
||||
option(PK_BUILD_STATIC_MAIN "Build static main" OFF)
|
@ -164,6 +164,7 @@ __ERROR:
|
||||
| Type Annotation | `def f(a:int, b:float=1)` | ✅ |
|
||||
| Generator | `yield i` | ✅ |
|
||||
| Decorator | `@cache` | ✅ |
|
||||
| Match Case | `match code: case 200:` | ✅ |
|
||||
|
||||
## Performance
|
||||
|
||||
|
@ -5,30 +5,30 @@ order: 100
|
||||
---
|
||||
|
||||
The following table shows the basic features of pkpy with respect to [cpython](https://github.com/python/cpython).
|
||||
The features marked with `YES` are supported, and the features marked with `NO` are not supported.
|
||||
|
||||
| Name | Example | Supported |
|
||||
| --------------- | ------------------------------- | --------- |
|
||||
| If Else | `if..else..elif` | YES |
|
||||
| Loop | `for/while/break/continue` | YES |
|
||||
| Function | `def f(x,*args,y=1):` | YES |
|
||||
| Subclass | `class A(B):` | YES |
|
||||
| List | `[1, 2, 'a']` | YES |
|
||||
| ListComp | `[i for i in range(5)]` | YES |
|
||||
| Slice | `a[1:2], a[:2], a[1:]` | YES |
|
||||
| Tuple | `(1, 2, 'a')` | YES |
|
||||
| Dict | `{'a': 1, 'b': 2}` | YES |
|
||||
| F-String | `f'value is {x}'` | YES |
|
||||
| Unpacking | `a, b = 1, 2` | YES |
|
||||
| Star Unpacking | `a, *b = [1, 2, 3]` | YES |
|
||||
| Exception | `raise/try..catch..finally` | YES |
|
||||
| Dynamic Code | `eval()/exec()` | YES |
|
||||
| Reflection | `hasattr()/getattr()/setattr()` | YES |
|
||||
| Import | `import/from..import` | YES |
|
||||
| Context Block | `with <expr> as <id>:` | YES |
|
||||
| Type Annotation | `def f(a:int, b:float=1)` | YES |
|
||||
| Generator | `yield i` | YES |
|
||||
| Decorator | `@cache` | YES |
|
||||
| If Else | `if..else..elif` | ✅ |
|
||||
| Loop | `for/while/break/continue` | ✅ |
|
||||
| Function | `def f(x,*args,y=1):` | ✅ |
|
||||
| Subclass | `class A(B):` | ✅ |
|
||||
| List | `[1, 2, 'a']` | ✅ |
|
||||
| ListComp | `[i for i in range(5)]` | ✅ |
|
||||
| Slice | `a[1:2], a[:2], a[1:]` | ✅ |
|
||||
| Tuple | `(1, 2, 'a')` | ✅ |
|
||||
| Dict | `{'a': 1, 'b': 2}` | ✅ |
|
||||
| F-String | `f'value is {x}'` | ✅ |
|
||||
| Unpacking | `a, b = 1, 2` | ✅ |
|
||||
| Star Unpacking | `a, *b = [1, 2, 3]` | ✅ |
|
||||
| Exception | `raise/try..catch..finally` | ✅ |
|
||||
| Dynamic Code | `eval()/exec()` | ✅ |
|
||||
| Reflection | `hasattr()/getattr()/setattr()` | ✅ |
|
||||
| Import | `import/from..import` | ✅ |
|
||||
| Context Block | `with <expr> as <id>:` | ✅ |
|
||||
| Type Annotation | `def f(a:int, b:float=1)` | ✅ |
|
||||
| Generator | `yield i` | ✅ |
|
||||
| Decorator | `@cache` | ✅ |
|
||||
| Match Case | `match code: case 200:` | ✅ |
|
||||
|
||||
## Supported magic methods
|
||||
|
||||
|
@ -36,4 +36,4 @@ The easiest way to test a feature is to [try it on your browser](https://pocketp
|
||||
5. In a starred unpacked assignment, e.g. `a, b, *c = x`, the starred variable can only be presented in the last position. `a, *b, c = x` is not supported.
|
||||
6. A `Tab` is equivalent to 4 spaces. You can mix `Tab` and spaces in indentation, but it is not recommended.
|
||||
7. A return, break, continue in try/except/with block will make the finally block not executed.
|
||||
|
||||
8. `match` is a keyword and `match..case` is equivalent to `if..elif..else`.
|
||||
|
@ -3,7 +3,7 @@ output: .retype
|
||||
url: https://pocketpy.dev
|
||||
branding:
|
||||
title: pocketpy
|
||||
label: v2.0.9
|
||||
label: v2.1.0
|
||||
logo: "./static/logo.png"
|
||||
favicon: "./static/logo.png"
|
||||
meta:
|
||||
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/str.h"
|
||||
#include "pocketpy/common/vector.h"
|
||||
#include "pocketpy/objects/sourcedata.h"
|
||||
#include "pocketpy/objects/error.h"
|
||||
#include <stdint.h>
|
||||
@ -9,26 +8,106 @@
|
||||
extern const char* TokenSymbols[];
|
||||
|
||||
typedef enum TokenIndex {
|
||||
TK_EOF, TK_EOL, TK_SOF,
|
||||
TK_ID, TK_NUM, TK_STR, TK_FSTR_BEGIN, TK_FSTR_CPNT, TK_FSTR_SPEC, TK_FSTR_END, TK_BYTES, TK_IMAG,
|
||||
TK_INDENT, TK_DEDENT,
|
||||
TK_EOF,
|
||||
TK_EOL,
|
||||
TK_SOF,
|
||||
TK_ID,
|
||||
TK_NUM,
|
||||
TK_STR,
|
||||
TK_FSTR_BEGIN,
|
||||
TK_FSTR_CPNT,
|
||||
TK_FSTR_SPEC,
|
||||
TK_FSTR_END,
|
||||
TK_BYTES,
|
||||
TK_IMAG,
|
||||
TK_INDENT,
|
||||
TK_DEDENT,
|
||||
/***************/
|
||||
TK_IS_NOT, TK_NOT_IN, TK_YIELD_FROM,
|
||||
TK_IS_NOT,
|
||||
TK_NOT_IN,
|
||||
TK_YIELD_FROM,
|
||||
/***************/
|
||||
TK_ADD, TK_IADD, TK_SUB, TK_ISUB,
|
||||
TK_MUL, TK_IMUL, TK_DIV, TK_IDIV, TK_FLOORDIV, TK_IFLOORDIV, TK_MOD, TK_IMOD,
|
||||
TK_AND, TK_IAND, TK_OR, TK_IOR, TK_XOR, TK_IXOR,
|
||||
TK_LSHIFT, TK_ILSHIFT, TK_RSHIFT, TK_IRSHIFT,
|
||||
TK_ADD,
|
||||
TK_IADD,
|
||||
TK_SUB,
|
||||
TK_ISUB,
|
||||
TK_MUL,
|
||||
TK_IMUL,
|
||||
TK_DIV,
|
||||
TK_IDIV,
|
||||
TK_FLOORDIV,
|
||||
TK_IFLOORDIV,
|
||||
TK_MOD,
|
||||
TK_IMOD,
|
||||
TK_AND,
|
||||
TK_IAND,
|
||||
TK_OR,
|
||||
TK_IOR,
|
||||
TK_XOR,
|
||||
TK_IXOR,
|
||||
TK_LSHIFT,
|
||||
TK_ILSHIFT,
|
||||
TK_RSHIFT,
|
||||
TK_IRSHIFT,
|
||||
/***************/
|
||||
TK_LPAREN, TK_RPAREN, TK_LBRACKET, TK_RBRACKET, TK_LBRACE, TK_RBRACE,
|
||||
TK_DOT, TK_DOTDOT, TK_DOTDOTDOT, TK_COMMA, TK_COLON, TK_SEMICOLON,
|
||||
TK_POW, TK_ARROW, TK_HASH, TK_DECORATOR,
|
||||
TK_GT, TK_LT, TK_ASSIGN, TK_EQ, TK_NE, TK_GE, TK_LE, TK_INVERT,
|
||||
TK_LPAREN,
|
||||
TK_RPAREN,
|
||||
TK_LBRACKET,
|
||||
TK_RBRACKET,
|
||||
TK_LBRACE,
|
||||
TK_RBRACE,
|
||||
TK_DOT,
|
||||
TK_DOTDOT,
|
||||
TK_DOTDOTDOT,
|
||||
TK_COMMA,
|
||||
TK_COLON,
|
||||
TK_SEMICOLON,
|
||||
TK_POW,
|
||||
TK_ARROW,
|
||||
TK_HASH,
|
||||
TK_DECORATOR,
|
||||
TK_GT,
|
||||
TK_LT,
|
||||
TK_ASSIGN,
|
||||
TK_EQ,
|
||||
TK_NE,
|
||||
TK_GE,
|
||||
TK_LE,
|
||||
TK_INVERT,
|
||||
/***************/
|
||||
TK_FALSE, TK_NONE, TK_TRUE, TK_AND_KW, TK_AS, TK_ASSERT, TK_BREAK, TK_CLASS, TK_CONTINUE,
|
||||
TK_DEF, TK_DEL, TK_ELIF, TK_ELSE, TK_EXCEPT, TK_FINALLY, TK_FOR, TK_FROM, TK_GLOBAL,
|
||||
TK_IF, TK_IMPORT, TK_IN, TK_IS, TK_LAMBDA, TK_NOT_KW, TK_OR_KW, TK_PASS, TK_RAISE, TK_RETURN,
|
||||
TK_TRY, TK_WHILE, TK_WITH, TK_YIELD,
|
||||
TK_FALSE,
|
||||
TK_NONE,
|
||||
TK_TRUE,
|
||||
TK_AND_KW,
|
||||
TK_AS,
|
||||
TK_ASSERT,
|
||||
TK_BREAK,
|
||||
TK_CLASS,
|
||||
TK_CONTINUE,
|
||||
TK_DEF,
|
||||
TK_DEL,
|
||||
TK_ELIF,
|
||||
TK_ELSE,
|
||||
TK_EXCEPT,
|
||||
TK_FINALLY,
|
||||
TK_FOR,
|
||||
TK_FROM,
|
||||
TK_GLOBAL,
|
||||
TK_IF,
|
||||
TK_IMPORT,
|
||||
TK_IN,
|
||||
TK_IS,
|
||||
TK_LAMBDA,
|
||||
TK_MATCH,
|
||||
TK_NOT_KW,
|
||||
TK_OR_KW,
|
||||
TK_PASS,
|
||||
TK_RAISE,
|
||||
TK_RETURN,
|
||||
TK_TRY,
|
||||
TK_WHILE,
|
||||
TK_WITH,
|
||||
TK_YIELD,
|
||||
/***************/
|
||||
TK__COUNT__
|
||||
} TokenIndex;
|
||||
@ -42,6 +121,7 @@ enum TokenValueIndex{
|
||||
|
||||
typedef struct TokenValue {
|
||||
enum TokenValueIndex index; // 0: empty
|
||||
|
||||
union {
|
||||
int64_t _i64; // 1
|
||||
double _f64; // 2
|
||||
@ -69,7 +149,8 @@ enum Precedence {
|
||||
/* https://docs.python.org/3/reference/expressions.html#comparisons
|
||||
* Unlike C, all comparison operations in Python have the same priority,
|
||||
* which is lower than that of any arithmetic, shifting or bitwise operation.
|
||||
* Also unlike C, expressions like a < b < c have the interpretation that is conventional in mathematics.
|
||||
* Also unlike C, expressions like a < b < c have the interpretation that is conventional in
|
||||
* mathematics.
|
||||
*/
|
||||
PREC_COMPARISION, // < > <= >= != ==, in / is / is not / not in
|
||||
PREC_BITWISE_OR, // |
|
||||
@ -86,4 +167,5 @@ enum Precedence {
|
||||
|
||||
Error* Lexer__process(SourceData_ src, Token** out_tokens, int* out_length);
|
||||
|
||||
#define Token__sv(self) (c11_sv){(self)->start, (self)->length}
|
||||
#define Token__sv(self) \
|
||||
(c11_sv) { (self)->start, (self)->length }
|
||||
|
@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
#define PK_VERSION "2.0.9"
|
||||
#define PK_VERSION "2.1.0"
|
||||
#define PK_VERSION_MAJOR 2
|
||||
#define PK_VERSION_MINOR 0
|
||||
#define PK_VERSION_PATCH 9
|
||||
#define PK_VERSION_MINOR 1
|
||||
#define PK_VERSION_PATCH 0
|
||||
|
||||
/*************** feature settings ***************/
|
||||
// Whether to compile os-related modules or not
|
||||
@ -12,6 +12,10 @@
|
||||
#define PK_ENABLE_OS 1
|
||||
#endif
|
||||
|
||||
#ifndef PK_ENABLE_WATCHDOG // can be overridden by cmake
|
||||
#define PK_ENABLE_WATCHDOG 0
|
||||
#endif
|
||||
|
||||
// GC min threshold
|
||||
#ifndef PK_GC_MIN_THRESHOLD // can be overridden by cmake
|
||||
#define PK_GC_MIN_THRESHOLD 32768
|
||||
@ -51,3 +55,9 @@
|
||||
#else
|
||||
#define PK_PLATFORM_SEP '/'
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#ifndef restrict
|
||||
#define restrict
|
||||
#endif
|
||||
#endif
|
||||
|
@ -23,6 +23,11 @@ typedef struct TraceInfo {
|
||||
py_TraceFunc func;
|
||||
} TraceInfo;
|
||||
|
||||
typedef struct WatchdogInfo {
|
||||
py_i64 timeout;
|
||||
py_i64 last_reset_time;
|
||||
} WatchdogInfo;
|
||||
|
||||
typedef struct VM {
|
||||
py_Frame* top_frame;
|
||||
|
||||
@ -48,6 +53,7 @@ typedef struct VM {
|
||||
py_StackRef curr_class;
|
||||
py_StackRef curr_decl_based_function;
|
||||
TraceInfo trace_info;
|
||||
WatchdogInfo watchdog_info;
|
||||
py_TValue vectorcall_buffer[PK_MAX_CO_VARNAMES];
|
||||
|
||||
InternedNames names;
|
||||
|
@ -47,7 +47,7 @@ typedef py_TValue* py_GlobalRef;
|
||||
typedef py_TValue* py_StackRef;
|
||||
/// An item reference to a container object. It invalidates when the container is modified.
|
||||
typedef py_TValue* py_ItemRef;
|
||||
/// An output reference for returning a value.
|
||||
/// An output reference for returning a value. Only use this for function arguments.
|
||||
typedef py_TValue* py_OutRef;
|
||||
|
||||
typedef struct py_Frame py_Frame;
|
||||
@ -90,7 +90,8 @@ enum py_CompileMode { EXEC_MODE, EVAL_MODE, SINGLE_MODE };
|
||||
|
||||
/// Initialize pocketpy and the default VM.
|
||||
PK_API void py_initialize();
|
||||
/// Finalize pocketpy and free all VMs.
|
||||
/// Finalize pocketpy and free all VMs. This opearation is irreversible.
|
||||
/// After this call, you cannot use any function from this header anymore.
|
||||
PK_API void py_finalize();
|
||||
/// Get the current VM index.
|
||||
PK_API int py_currentvm();
|
||||
@ -110,6 +111,16 @@ PK_API void py_sys_settrace(py_TraceFunc func);
|
||||
/// Setup the callbacks for the current VM.
|
||||
PK_API py_Callbacks* py_callbacks();
|
||||
|
||||
/// Begin the watchdog with a timeout in milliseconds.
|
||||
/// `PK_ENABLE_WATCHDOG` must be defined to `1` to use this feature.
|
||||
/// You need to call `py_watchdog_reset()` periodically to keep the watchdog alive.
|
||||
/// If the timeout is reached, `TimeoutError` will be raised.
|
||||
PK_API void py_watchdog_begin(py_i64 timeout);
|
||||
/// Reset the watchdog.
|
||||
PK_API void py_watchdog_reset();
|
||||
/// End the watchdog.
|
||||
PK_API void py_watchdog_end();
|
||||
|
||||
/// Get the current source location of the frame.
|
||||
PK_API const char* py_Frame_sourceloc(py_Frame* frame, int* lineno);
|
||||
/// Python equivalent to `globals()` with respect to the given frame.
|
||||
@ -552,6 +563,7 @@ PK_API void py_clearexc(py_StackRef p0);
|
||||
#define NameError(n) py_exception(tp_NameError, "name '%n' is not defined", (n))
|
||||
#define TypeError(...) py_exception(tp_TypeError, __VA_ARGS__)
|
||||
#define RuntimeError(...) py_exception(tp_RuntimeError, __VA_ARGS__)
|
||||
#define TimeoutError(...) py_exception(tp_TimeoutError, __VA_ARGS__)
|
||||
#define OSError(...) py_exception(tp_OSError, __VA_ARGS__)
|
||||
#define ValueError(...) py_exception(tp_ValueError, __VA_ARGS__)
|
||||
#define IndexError(...) py_exception(tp_IndexError, __VA_ARGS__)
|
||||
@ -756,6 +768,7 @@ enum py_PredefinedType {
|
||||
tp_IndexError,
|
||||
tp_ValueError,
|
||||
tp_RuntimeError,
|
||||
tp_TimeoutError,
|
||||
tp_ZeroDivisionError,
|
||||
tp_NameError,
|
||||
tp_UnboundLocalError,
|
||||
|
@ -56,6 +56,7 @@ OPCODE(IS_OP)
|
||||
OPCODE(CONTAINS_OP)
|
||||
/**************************/
|
||||
OPCODE(JUMP_FORWARD)
|
||||
OPCODE(POP_JUMP_IF_NOT_MATCH)
|
||||
OPCODE(POP_JUMP_IF_FALSE)
|
||||
OPCODE(POP_JUMP_IF_TRUE)
|
||||
OPCODE(JUMP_IF_TRUE_OR_POP)
|
||||
|
@ -25,6 +25,19 @@ def currentvm() -> int:
|
||||
"""Return the current VM index."""
|
||||
|
||||
|
||||
def watchdog_begin(timeout: int):
|
||||
"""
|
||||
Begin the watchdog with a timeout in milliseconds.
|
||||
`PK_ENABLE_WATCHDOG` must be defined to `1` to use this feature.
|
||||
You need to call `watchdog_reset()` periodically to keep the watchdog alive.
|
||||
If the timeout is reached, `TimeoutError` will be raised.
|
||||
"""
|
||||
def watchdog_reset():
|
||||
"""Reset the watchdog."""
|
||||
def watchdog_end():
|
||||
"""End the watchdog."""
|
||||
|
||||
|
||||
class ComputeThread:
|
||||
def __init__(self, vm_index: Literal[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]): ...
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
#include "pocketpy/compiler/compiler.h"
|
||||
#include "pocketpy/common/vector.h"
|
||||
#include "pocketpy/compiler/lexer.h"
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#include "pocketpy/objects/sourcedata.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
@ -479,13 +479,7 @@ bool TupleExpr__emit_store(Expr* self_, Ctx* ctx) {
|
||||
}
|
||||
|
||||
if(starred_i == -1) {
|
||||
Bytecode* prev = c11__at(Bytecode, &ctx->co->codes, ctx->co->codes.length - 1);
|
||||
if(prev->op == OP_BUILD_TUPLE && prev->arg == self->itemCount) {
|
||||
// build tuple and unpack it is meaningless
|
||||
Ctx__revert_last_emit_(ctx);
|
||||
} else {
|
||||
Ctx__emit_(ctx, OP_UNPACK_SEQUENCE, self->itemCount, self->line);
|
||||
}
|
||||
} else {
|
||||
// starred assignment target must be in a tuple
|
||||
if(self->itemCount == 1) return false;
|
||||
@ -1377,6 +1371,15 @@ static bool is_expression(Compiler* self, bool allow_slice) {
|
||||
|
||||
#define match(expected) (curr()->type == expected ? (++self->i) : 0)
|
||||
|
||||
static bool match_id_by_str(Compiler* self, const char* name) {
|
||||
if(curr()->type == TK_ID) {
|
||||
bool ok = c11__sveq2(Token__sv(curr()), name);
|
||||
if(ok) advance();
|
||||
return ok;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool match_newlines_impl(Compiler* self) {
|
||||
bool consumed = false;
|
||||
if(curr()->type == TK_EOL) {
|
||||
@ -1969,10 +1972,10 @@ static Error* consume_type_hints_sv(Compiler* self, c11_sv* out) {
|
||||
|
||||
static Error* compile_stmt(Compiler* self);
|
||||
|
||||
static Error* compile_block_body(Compiler* self, PrattCallback callback) {
|
||||
static Error* compile_block_body(Compiler* self) {
|
||||
Error* err;
|
||||
assert(callback != NULL);
|
||||
consume(TK_COLON);
|
||||
|
||||
if(curr()->type != TK_EOL && curr()->type != TK_EOF) {
|
||||
while(true) {
|
||||
check(compile_stmt(self));
|
||||
@ -1988,7 +1991,7 @@ static Error* compile_block_body(Compiler* self, PrattCallback callback) {
|
||||
consume(TK_INDENT);
|
||||
while(curr()->type != TK_DEDENT) {
|
||||
match_newlines();
|
||||
check(callback(self));
|
||||
check(compile_stmt(self));
|
||||
match_newlines();
|
||||
}
|
||||
consume(TK_DEDENT);
|
||||
@ -2000,7 +2003,7 @@ static Error* compile_if_stmt(Compiler* self) {
|
||||
check(EXPR(self)); // condition
|
||||
Ctx__s_emit_top(ctx());
|
||||
int patch = Ctx__emit_(ctx(), OP_POP_JUMP_IF_FALSE, BC_NOARG, prev()->line);
|
||||
err = compile_block_body(self, compile_stmt);
|
||||
err = compile_block_body(self);
|
||||
if(err) return err;
|
||||
if(match(TK_ELIF)) {
|
||||
int exit_patch = Ctx__emit_(ctx(), OP_JUMP_FORWARD, BC_NOARG, prev()->line);
|
||||
@ -2010,7 +2013,7 @@ static Error* compile_if_stmt(Compiler* self) {
|
||||
} else if(match(TK_ELSE)) {
|
||||
int exit_patch = Ctx__emit_(ctx(), OP_JUMP_FORWARD, BC_NOARG, prev()->line);
|
||||
Ctx__patch_jump(ctx(), patch);
|
||||
check(compile_block_body(self, compile_stmt));
|
||||
check(compile_block_body(self));
|
||||
Ctx__patch_jump(ctx(), exit_patch);
|
||||
} else {
|
||||
Ctx__patch_jump(ctx(), patch);
|
||||
@ -2018,6 +2021,54 @@ static Error* compile_if_stmt(Compiler* self) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Error* compile_match_case(Compiler* self, c11_vector* patches) {
|
||||
Error* err;
|
||||
bool is_case_default = false;
|
||||
|
||||
check(EXPR(self)); // condition
|
||||
Ctx__s_emit_top(ctx());
|
||||
|
||||
consume(TK_COLON);
|
||||
|
||||
bool consumed = match_newlines();
|
||||
if(!consumed) return SyntaxError(self, "expected a new line after ':'");
|
||||
|
||||
consume(TK_INDENT);
|
||||
while(curr()->type != TK_DEDENT) {
|
||||
match_newlines();
|
||||
|
||||
if(match_id_by_str(self, "case")) {
|
||||
if(is_case_default) return SyntaxError(self, "case _: must be the last one");
|
||||
is_case_default = match_id_by_str(self, "_");
|
||||
|
||||
if(!is_case_default) {
|
||||
Ctx__emit_(ctx(), OP_DUP_TOP, BC_NOARG, prev()->line);
|
||||
check(EXPR(self)); // expr
|
||||
Ctx__s_emit_top(ctx());
|
||||
int patch = Ctx__emit_(ctx(), OP_POP_JUMP_IF_NOT_MATCH, BC_NOARG, prev()->line);
|
||||
check(compile_block_body(self));
|
||||
int break_patch = Ctx__emit_(ctx(), OP_JUMP_FORWARD, BC_NOARG, prev()->line);
|
||||
c11_vector__push(int, patches, break_patch);
|
||||
Ctx__patch_jump(ctx(), patch);
|
||||
} else {
|
||||
check(compile_block_body(self));
|
||||
}
|
||||
} else {
|
||||
return SyntaxError(self, "expected 'case', got '%s'", TokenSymbols[curr()->type]);
|
||||
}
|
||||
|
||||
match_newlines();
|
||||
}
|
||||
consume(TK_DEDENT);
|
||||
|
||||
for(int i = 0; i < patches->length; i++) {
|
||||
int patch = c11__getitem(int, patches, i);
|
||||
Ctx__patch_jump(ctx(), patch);
|
||||
}
|
||||
Ctx__emit_(ctx(), OP_POP_TOP, BC_NOARG, prev()->line);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Error* compile_while_loop(Compiler* self) {
|
||||
Error* err;
|
||||
int block = Ctx__enter_block(ctx(), CodeBlockType_WHILE_LOOP);
|
||||
@ -2025,13 +2076,13 @@ static Error* compile_while_loop(Compiler* self) {
|
||||
check(EXPR(self)); // condition
|
||||
Ctx__s_emit_top(ctx());
|
||||
int patch = Ctx__emit_(ctx(), OP_POP_JUMP_IF_FALSE, BC_NOARG, prev()->line);
|
||||
check(compile_block_body(self, compile_stmt));
|
||||
check(compile_block_body(self));
|
||||
Ctx__emit_jump(ctx(), block_start, BC_KEEPLINE);
|
||||
Ctx__patch_jump(ctx(), patch);
|
||||
Ctx__exit_block(ctx());
|
||||
// optional else clause
|
||||
if(match(TK_ELSE)) {
|
||||
check(compile_block_body(self, compile_stmt));
|
||||
check(compile_block_body(self));
|
||||
CodeBlock* p_block = c11__at(CodeBlock, &ctx()->co->blocks, block);
|
||||
p_block->end2 = ctx()->co->codes.length;
|
||||
}
|
||||
@ -2054,12 +2105,12 @@ static Error* compile_for_loop(Compiler* self) {
|
||||
// this error occurs in `vars` instead of this line, but...nevermind
|
||||
return SyntaxError(self, "invalid syntax");
|
||||
}
|
||||
check(compile_block_body(self, compile_stmt));
|
||||
check(compile_block_body(self));
|
||||
Ctx__emit_jump(ctx(), block_start, BC_KEEPLINE);
|
||||
Ctx__exit_block(ctx());
|
||||
// optional else clause
|
||||
if(match(TK_ELSE)) {
|
||||
check(compile_block_body(self, compile_stmt));
|
||||
check(compile_block_body(self));
|
||||
CodeBlock* p_block = c11__at(CodeBlock, &ctx()->co->blocks, block);
|
||||
p_block->end2 = ctx()->co->codes.length;
|
||||
}
|
||||
@ -2120,7 +2171,7 @@ Error* try_compile_assignment(Compiler* self, bool* is_assign) {
|
||||
}
|
||||
case TK_ASSIGN: {
|
||||
consume(TK_ASSIGN);
|
||||
int n = 0;
|
||||
int n = 0; // assignment count
|
||||
|
||||
if(match(TK_YIELD_FROM)) {
|
||||
check(compile_yield_from(self, prev()->line));
|
||||
@ -2289,7 +2340,7 @@ static Error* compile_function(Compiler* self, int decorators) {
|
||||
consume(TK_RPAREN);
|
||||
}
|
||||
if(match(TK_ARROW)) check(consume_type_hints(self));
|
||||
check(compile_block_body(self, compile_stmt));
|
||||
check(compile_block_body(self));
|
||||
check(pop_context(self));
|
||||
|
||||
if(decl->code.codes.length >= 2) {
|
||||
@ -2354,7 +2405,7 @@ static Error* compile_class(Compiler* self, int decorators) {
|
||||
if(it->is_compiling_class) return SyntaxError(self, "nested class is not allowed");
|
||||
}
|
||||
ctx()->is_compiling_class = true;
|
||||
check(compile_block_body(self, compile_stmt));
|
||||
check(compile_block_body(self));
|
||||
ctx()->is_compiling_class = false;
|
||||
|
||||
Ctx__s_emit_decorators(ctx(), decorators);
|
||||
@ -2489,7 +2540,7 @@ static Error* compile_try_except(Compiler* self) {
|
||||
|
||||
Ctx__enter_block(ctx(), CodeBlockType_TRY);
|
||||
Ctx__emit_(ctx(), OP_TRY_ENTER, BC_NOARG, prev()->line);
|
||||
check(compile_block_body(self, compile_stmt));
|
||||
check(compile_block_body(self));
|
||||
|
||||
// https://docs.python.org/3/reference/compound_stmts.html#finally-clause
|
||||
/* If finally is present, it specifies a ‘cleanup’ handler. The try clause is executed,
|
||||
@ -2515,7 +2566,7 @@ static Error* compile_try_except(Compiler* self) {
|
||||
Ctx__emit_(ctx(), OP_BEGIN_FINALLY, BC_NOARG, prev()->line);
|
||||
// finally only, no except block
|
||||
Ctx__enter_block(ctx(), CodeBlockType_FINALLY);
|
||||
check(compile_block_body(self, compile_stmt));
|
||||
check(compile_block_body(self));
|
||||
Ctx__exit_block(ctx());
|
||||
Ctx__emit_(ctx(), OP_END_FINALLY, BC_NOARG, BC_KEEPLINE);
|
||||
// re-raise if needed
|
||||
@ -2551,7 +2602,7 @@ static Error* compile_try_except(Compiler* self) {
|
||||
Ctx__emit_store_name(ctx(), name_scope(self), as_name, BC_KEEPLINE);
|
||||
}
|
||||
Ctx__enter_block(ctx(), CodeBlockType_EXCEPT);
|
||||
check(compile_block_body(self, compile_stmt));
|
||||
check(compile_block_body(self));
|
||||
Ctx__exit_block(ctx());
|
||||
Ctx__emit_(ctx(), OP_END_EXC_HANDLING, BC_NOARG, BC_KEEPLINE);
|
||||
patches[patches_length++] = Ctx__emit_(ctx(), OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE);
|
||||
@ -2568,7 +2619,7 @@ static Error* compile_try_except(Compiler* self) {
|
||||
if(match(TK_FINALLY)) {
|
||||
Ctx__emit_(ctx(), OP_BEGIN_FINALLY, BC_NOARG, prev()->line);
|
||||
Ctx__enter_block(ctx(), CodeBlockType_FINALLY);
|
||||
check(compile_block_body(self, compile_stmt));
|
||||
check(compile_block_body(self));
|
||||
Ctx__exit_block(ctx());
|
||||
Ctx__emit_(ctx(), OP_END_FINALLY, BC_NOARG, BC_KEEPLINE);
|
||||
}
|
||||
@ -2629,6 +2680,13 @@ static Error* compile_stmt(Compiler* self) {
|
||||
break;
|
||||
/*************************************************/
|
||||
case TK_IF: check(compile_if_stmt(self)); break;
|
||||
case TK_MATCH: {
|
||||
c11_vector patches;
|
||||
c11_vector__ctor(&patches, sizeof(int));
|
||||
check(compile_match_case(self, &patches));
|
||||
c11_vector__dtor(&patches);
|
||||
break;
|
||||
}
|
||||
case TK_WHILE: check(compile_while_loop(self)); break;
|
||||
case TK_FOR: check(compile_for_loop(self)); break;
|
||||
case TK_IMPORT: check(compile_normal_import(self)); break;
|
||||
@ -2701,7 +2759,7 @@ static Error* compile_stmt(Compiler* self) {
|
||||
// discard `__enter__()`'s return value
|
||||
Ctx__emit_(ctx(), OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
|
||||
}
|
||||
check(compile_block_body(self, compile_stmt));
|
||||
check(compile_block_body(self));
|
||||
Ctx__emit_(ctx(), OP_WITH_EXIT, BC_NOARG, prev()->line);
|
||||
Ctx__exit_block(ctx());
|
||||
} break;
|
||||
|
@ -1,4 +1,3 @@
|
||||
#include "pocketpy/common/smallmap.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/common/vector.h"
|
||||
#include "pocketpy/compiler/lexer.h"
|
||||
@ -712,6 +711,7 @@ const char* TokenSymbols[] = {
|
||||
"in",
|
||||
"is",
|
||||
"lambda",
|
||||
"match",
|
||||
"not",
|
||||
"or",
|
||||
"pass",
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include "pocketpy/objects/error.h"
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
static bool stack_format_object(VM* self, c11_sv spec);
|
||||
|
||||
@ -107,6 +108,18 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
}
|
||||
}
|
||||
|
||||
#if PK_ENABLE_WATCHDOG
|
||||
if(self->watchdog_info.timeout > 0){
|
||||
py_i64 now = clock() / (CLOCKS_PER_SEC / 1000);
|
||||
py_i64 delta = now - self->watchdog_info.last_reset_time;
|
||||
if(delta > self->watchdog_info.timeout) {
|
||||
self->watchdog_info.last_reset_time = now;
|
||||
TimeoutError("watchdog timeout");
|
||||
goto __ERROR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
pk_print_stack(self, frame, byte);
|
||||
#endif
|
||||
@ -619,6 +632,13 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
}
|
||||
/*****************************************/
|
||||
case OP_JUMP_FORWARD: DISPATCH_JUMP((int16_t)byte.arg);
|
||||
case OP_POP_JUMP_IF_NOT_MATCH: {
|
||||
int res = py_equal(SECOND(), TOP());
|
||||
if(res < 0) goto __ERROR;
|
||||
STACK_SHRINK(2);
|
||||
if(!res) DISPATCH_JUMP((int16_t)byte.arg);
|
||||
DISPATCH();
|
||||
}
|
||||
case OP_POP_JUMP_IF_FALSE: {
|
||||
int res = py_bool(TOP());
|
||||
if(res < 0) goto __ERROR;
|
||||
|
@ -192,7 +192,7 @@ const char* py_Frame_sourceloc(py_Frame* self, int* lineno) {
|
||||
return loc.src->filename->data;
|
||||
}
|
||||
|
||||
void py_Frame_newglobals(py_Frame* frame, py_Ref out) {
|
||||
void py_Frame_newglobals(py_Frame* frame, py_OutRef out) {
|
||||
if(!frame) {
|
||||
pk_mappingproxy__namedict(out, &pk_current_vm->main);
|
||||
return;
|
||||
@ -204,7 +204,7 @@ void py_Frame_newglobals(py_Frame* frame, py_Ref out) {
|
||||
}
|
||||
}
|
||||
|
||||
void py_Frame_newlocals(py_Frame* frame, py_Ref out) {
|
||||
void py_Frame_newlocals(py_Frame* frame, py_OutRef out) {
|
||||
if(!frame) {
|
||||
py_newdict(out);
|
||||
return;
|
||||
|
@ -170,6 +170,7 @@ void VM__ctor(VM* self) {
|
||||
INJECT_BUILTIN_EXC(IndexError, tp_Exception);
|
||||
INJECT_BUILTIN_EXC(ValueError, tp_Exception);
|
||||
INJECT_BUILTIN_EXC(RuntimeError, tp_Exception);
|
||||
INJECT_BUILTIN_EXC(TimeoutError, tp_Exception);
|
||||
INJECT_BUILTIN_EXC(ZeroDivisionError, tp_Exception);
|
||||
INJECT_BUILTIN_EXC(NameError, tp_Exception);
|
||||
INJECT_BUILTIN_EXC(UnboundLocalError, tp_Exception);
|
||||
|
@ -580,7 +580,7 @@ bool py_pickle_loads_body(const unsigned char* p, int memo_length, c11_smallmap_
|
||||
}
|
||||
case PKL_BUILD_LIST: {
|
||||
int length = pkl__read_int(&p);
|
||||
py_OutRef val = py_retval();
|
||||
py_Ref val = py_retval();
|
||||
py_newlistn(val, length);
|
||||
for(int i = length - 1; i >= 0; i--) {
|
||||
py_StackRef item = py_peek(-1);
|
||||
@ -592,7 +592,7 @@ bool py_pickle_loads_body(const unsigned char* p, int memo_length, c11_smallmap_
|
||||
}
|
||||
case PKL_BUILD_TUPLE: {
|
||||
int length = pkl__read_int(&p);
|
||||
py_OutRef val = py_retval();
|
||||
py_Ref val = py_retval();
|
||||
py_Ref p = py_newtuple(val, length);
|
||||
for(int i = length - 1; i >= 0; i--) {
|
||||
p[i] = *py_peek(-1);
|
||||
@ -603,7 +603,7 @@ bool py_pickle_loads_body(const unsigned char* p, int memo_length, c11_smallmap_
|
||||
}
|
||||
case PKL_BUILD_DICT: {
|
||||
int length = pkl__read_int(&p);
|
||||
py_OutRef val = py_pushtmp();
|
||||
py_Ref val = py_pushtmp();
|
||||
py_newdict(val);
|
||||
py_StackRef begin = py_peek(-1) - 2 * length;
|
||||
py_StackRef end = py_peek(-1);
|
||||
|
@ -3,7 +3,6 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
@ -79,6 +78,46 @@ static bool pkpy_currentvm(int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if PK_ENABLE_WATCHDOG
|
||||
void py_watchdog_begin(py_i64 timeout) {
|
||||
WatchdogInfo* info = &pk_current_vm->watchdog_info;
|
||||
info->timeout = timeout;
|
||||
py_watchdog_reset();
|
||||
}
|
||||
|
||||
void py_watchdog_reset() {
|
||||
WatchdogInfo* info = &pk_current_vm->watchdog_info;
|
||||
info->last_reset_time = clock() / (CLOCKS_PER_SEC / 1000);
|
||||
}
|
||||
|
||||
void py_watchdog_end() {
|
||||
WatchdogInfo* info = &pk_current_vm->watchdog_info;
|
||||
info->timeout = 0;
|
||||
}
|
||||
|
||||
static bool pkpy_watchdog_begin(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
PY_CHECK_ARG_TYPE(0, tp_int);
|
||||
py_watchdog_begin(py_toint(argv));
|
||||
py_newnone(py_retval());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool pkpy_watchdog_reset(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(0);
|
||||
py_watchdog_reset();
|
||||
py_newnone(py_retval());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool pkpy_watchdog_end(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(0);
|
||||
py_watchdog_end();
|
||||
py_newnone(py_retval());
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef struct c11_ComputeThread c11_ComputeThread;
|
||||
|
||||
typedef struct {
|
||||
@ -467,6 +506,12 @@ void pk__add_module_pkpy() {
|
||||
|
||||
py_bindfunc(mod, "currentvm", pkpy_currentvm);
|
||||
|
||||
#if PK_ENABLE_WATCHDOG
|
||||
py_bindfunc(mod, "watchdog_begin", pkpy_watchdog_begin);
|
||||
py_bindfunc(mod, "watchdog_reset", pkpy_watchdog_reset);
|
||||
py_bindfunc(mod, "watchdog_end", pkpy_watchdog_end);
|
||||
#endif
|
||||
|
||||
pk_ComputeThread__register(mod);
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,9 @@
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/common/math.h"
|
||||
|
||||
|
||||
static bool isclose(float a, float b) { return fabs(a - b) < 1e-4; }
|
||||
|
||||
#define DEFINE_VEC_FIELD(name, T, Tc, field) \
|
||||
@ -544,7 +544,7 @@ static bool mat3x3__eq__(int argc, py_Ref argv) {
|
||||
|
||||
DEFINE_BOOL_NE(mat3x3, mat3x3__eq__)
|
||||
|
||||
static void matmul(const c11_mat3x3* lhs, const c11_mat3x3* rhs, c11_mat3x3* out) {
|
||||
static void matmul(const c11_mat3x3* lhs, const c11_mat3x3* rhs, c11_mat3x3* restrict out) {
|
||||
out->_11 = lhs->_11 * rhs->_11 + lhs->_12 * rhs->_21 + lhs->_13 * rhs->_31;
|
||||
out->_12 = lhs->_11 * rhs->_12 + lhs->_12 * rhs->_22 + lhs->_13 * rhs->_32;
|
||||
out->_13 = lhs->_11 * rhs->_13 + lhs->_12 * rhs->_23 + lhs->_13 * rhs->_33;
|
||||
@ -562,7 +562,7 @@ static float determinant(const c11_mat3x3* m) {
|
||||
m->_13 * (m->_21 * m->_32 - m->_22 * m->_31);
|
||||
}
|
||||
|
||||
static bool inverse(const c11_mat3x3* m, c11_mat3x3* out) {
|
||||
static bool inverse(const c11_mat3x3* m, c11_mat3x3* restrict out) {
|
||||
float det = determinant(m);
|
||||
if(isclose(det, 0)) return false;
|
||||
float invdet = 1.0f / det;
|
||||
@ -578,9 +578,9 @@ static bool inverse(const c11_mat3x3* m, c11_mat3x3* out) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void trs(c11_vec2 t, float r, c11_vec2 s, c11_mat3x3* out) {
|
||||
float cr = cos(r);
|
||||
float sr = sin(r);
|
||||
static void trs(c11_vec2 t, float r, c11_vec2 s, c11_mat3x3* restrict out) {
|
||||
float cr = cosf(r);
|
||||
float sr = sinf(r);
|
||||
// clang-format off
|
||||
*out = (c11_mat3x3){
|
||||
._11 = s.x * cr, ._12 = -s.y * sr, ._13 = t.x,
|
||||
|
@ -500,12 +500,12 @@ static bool builtins_locals(int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void py_newglobals(py_Ref out) {
|
||||
void py_newglobals(py_OutRef out) {
|
||||
py_Frame* frame = pk_current_vm->top_frame;
|
||||
py_Frame_newglobals(frame, out);
|
||||
}
|
||||
|
||||
void py_newlocals(py_Ref out) {
|
||||
void py_newlocals(py_OutRef out) {
|
||||
py_Frame* frame = pk_current_vm->top_frame;
|
||||
py_Frame_newlocals(frame, out);
|
||||
}
|
||||
|
@ -266,7 +266,7 @@ static bool dict__new__(int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void py_newdict(py_Ref out) {
|
||||
void py_newdict(py_OutRef out) {
|
||||
Dict* ud = py_newobject(out, tp_dict, 0, sizeof(Dict));
|
||||
Dict__ctor(ud, 7, 8);
|
||||
}
|
||||
|
@ -1,16 +1,15 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
|
||||
void py_newlist(py_Ref out) {
|
||||
void py_newlist(py_OutRef out) {
|
||||
List* ud = py_newobject(out, tp_list, 0, sizeof(List));
|
||||
c11_vector__ctor(ud, sizeof(py_TValue));
|
||||
}
|
||||
|
||||
void py_newlistn(py_Ref out, int n) {
|
||||
void py_newlistn(py_OutRef out, int n) {
|
||||
py_newlist(out);
|
||||
List* ud = py_touserdata(out);
|
||||
c11_vector__reserve(ud, n);
|
||||
|
@ -1,11 +1,10 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
void py_newslice(py_Ref out) {
|
||||
void py_newslice(py_OutRef out) {
|
||||
VM* vm = pk_current_vm;
|
||||
PyObject* obj = ManagedHeap__gcnew(&vm->heap, tp_slice, 3, 0);
|
||||
out->type = tp_slice;
|
||||
|
@ -6,9 +6,9 @@
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
|
||||
void py_newstr(py_Ref out, const char* data) { py_newstrv(out, (c11_sv){data, strlen(data)}); }
|
||||
void py_newstr(py_OutRef out, const char* data) { py_newstrv(out, (c11_sv){data, strlen(data)}); }
|
||||
|
||||
char* py_newstrn(py_Ref out, int size) {
|
||||
char* py_newstrn(py_OutRef out, int size) {
|
||||
if(size < 8) {
|
||||
out->type = tp_str;
|
||||
out->is_ptr = false;
|
||||
@ -42,7 +42,7 @@ void py_newfstr(py_OutRef out, const char* fmt, ...) {
|
||||
c11_sbuf__py_submit(&buf, out);
|
||||
}
|
||||
|
||||
unsigned char* py_newbytes(py_Ref out, int size) {
|
||||
unsigned char* py_newbytes(py_OutRef out, int size) {
|
||||
ManagedHeap* heap = &pk_current_vm->heap;
|
||||
// 4 bytes size + data
|
||||
PyObject* obj = ManagedHeap__gcnew(heap, tp_bytes, 0, sizeof(c11_bytes) + size);
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
py_ObjectRef py_newtuple(py_Ref out, int n) {
|
||||
py_ObjectRef py_newtuple(py_OutRef out, int n) {
|
||||
VM* vm = pk_current_vm;
|
||||
PyObject* obj = ManagedHeap__gcnew(&vm->heap, tp_tuple, n, 0);
|
||||
out->type = tp_tuple;
|
||||
|
@ -7,42 +7,42 @@
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/compiler/compiler.h"
|
||||
|
||||
void py_newint(py_Ref out, int64_t val) {
|
||||
void py_newint(py_OutRef out, py_i64 val) {
|
||||
out->type = tp_int;
|
||||
out->is_ptr = false;
|
||||
out->_i64 = val;
|
||||
}
|
||||
|
||||
void py_newfloat(py_Ref out, double val) {
|
||||
void py_newfloat(py_OutRef out, py_f64 val) {
|
||||
out->type = tp_float;
|
||||
out->is_ptr = false;
|
||||
out->_f64 = val;
|
||||
}
|
||||
|
||||
void py_newbool(py_Ref out, bool val) {
|
||||
void py_newbool(py_OutRef out, bool val) {
|
||||
out->type = tp_bool;
|
||||
out->is_ptr = false;
|
||||
out->_bool = val;
|
||||
}
|
||||
|
||||
void py_newnone(py_Ref out) {
|
||||
void py_newnone(py_OutRef out) {
|
||||
out->type = tp_NoneType;
|
||||
out->is_ptr = false;
|
||||
}
|
||||
|
||||
void py_newnotimplemented(py_Ref out) {
|
||||
void py_newnotimplemented(py_OutRef out) {
|
||||
out->type = tp_NotImplementedType;
|
||||
out->is_ptr = false;
|
||||
}
|
||||
|
||||
void py_newellipsis(py_Ref out) {
|
||||
void py_newellipsis(py_OutRef out) {
|
||||
out->type = tp_ellipsis;
|
||||
out->is_ptr = false;
|
||||
}
|
||||
|
||||
void py_newnil(py_Ref out) { out->type = 0; }
|
||||
void py_newnil(py_OutRef out) { out->type = 0; }
|
||||
|
||||
void py_newnativefunc(py_Ref out, py_CFunction f) {
|
||||
void py_newnativefunc(py_OutRef out, py_CFunction f) {
|
||||
out->type = tp_nativefunc;
|
||||
out->is_ptr = false;
|
||||
out->_cfunc = f;
|
||||
@ -90,7 +90,7 @@ void py_bind(py_Ref obj, const char* sig, py_CFunction f) {
|
||||
}
|
||||
|
||||
py_Name
|
||||
py_newfunction(py_Ref out, const char* sig, py_CFunction f, const char* docstring, int slots) {
|
||||
py_newfunction(py_OutRef out, const char* sig, py_CFunction f, const char* docstring, int slots) {
|
||||
char buffer[256];
|
||||
snprintf(buffer, sizeof(buffer), "def %s: pass", sig);
|
||||
// fn(a, b, *c, d=1) -> None
|
||||
@ -118,13 +118,13 @@ py_Name
|
||||
return decl_name;
|
||||
}
|
||||
|
||||
void py_newboundmethod(py_Ref out, py_Ref self, py_Ref func) {
|
||||
void py_newboundmethod(py_OutRef out, py_Ref self, py_Ref func) {
|
||||
py_newobject(out, tp_boundmethod, 2, 0);
|
||||
py_setslot(out, 0, self);
|
||||
py_setslot(out, 1, func);
|
||||
}
|
||||
|
||||
void* py_newobject(py_Ref out, py_Type type, int slots, int udsize) {
|
||||
void* py_newobject(py_OutRef out, py_Type type, int slots, int udsize) {
|
||||
ManagedHeap* heap = &pk_current_vm->heap;
|
||||
PyObject* obj = ManagedHeap__gcnew(heap, type, slots, udsize);
|
||||
out->type = type;
|
||||
|
@ -124,11 +124,51 @@ else:
|
||||
x = 3
|
||||
assert x == 2
|
||||
|
||||
# t = 0
|
||||
# for i in range(5):
|
||||
# try:
|
||||
# break
|
||||
# except:
|
||||
# pass
|
||||
# t = 1
|
||||
# assert t == 0
|
||||
# match case
|
||||
|
||||
case, _ = 1, 2
|
||||
assert case == 1 and _ == 2
|
||||
|
||||
match (404 * 1):
|
||||
case 200:
|
||||
assert False
|
||||
case 404:
|
||||
assert True
|
||||
case _: assert False
|
||||
|
||||
match (555 * 1):
|
||||
case 200:
|
||||
assert False
|
||||
case 404: assert False
|
||||
case _:
|
||||
assert True
|
||||
|
||||
match (555 * 1):
|
||||
case 200:
|
||||
assert False
|
||||
case 404:
|
||||
assert False
|
||||
# no default case
|
||||
|
||||
|
||||
def f(case):
|
||||
match case:
|
||||
case 200:
|
||||
return True
|
||||
case 404:
|
||||
return False
|
||||
case _:
|
||||
return False
|
||||
|
||||
assert f(200) == True
|
||||
|
||||
# extras
|
||||
|
||||
t = 0
|
||||
for i in range(5):
|
||||
try:
|
||||
break
|
||||
except:
|
||||
pass
|
||||
t = 1
|
||||
assert t == 0
|
||||
|
@ -149,3 +149,12 @@ a = [(0, 1), (1, 1), (1, 2)]
|
||||
b = sorted(a, key=lambda x: x[0])
|
||||
if b != [(0, 1), (1, 1), (1, 2)]:
|
||||
assert False, b
|
||||
|
||||
# https://github.com/pocketpy/pocketpy/issues/367
|
||||
a = 10 if False else 5
|
||||
assert a == 5
|
||||
|
||||
a, b, c = (1, 2, 3) if True else (4, 5, 6)
|
||||
assert a == 1
|
||||
assert b == 2
|
||||
assert c == 3
|
Loading…
x
Reference in New Issue
Block a user