Compare commits

...

11 Commits

Author SHA1 Message Date
blueloveTH
26a12bb640 ... 2024-08-12 13:51:44 +08:00
blueloveTH
26c553eb9a ... 2024-08-12 13:41:42 +08:00
blueloveTH
a5725824b4 ... 2024-08-12 13:38:29 +08:00
blueloveTH
b01234d27e ... 2024-08-12 13:37:09 +08:00
blueloveTH
e2d4f57859 ... 2024-08-12 13:35:05 +08:00
blueloveTH
8b32296c9c ... 2024-08-12 13:25:52 +08:00
blueloveTH
81fe369b44 ... 2024-08-12 13:24:03 +08:00
blueloveTH
c016a728b6 add easing module 2024-08-12 13:21:24 +08:00
blueloveTH
04229f438f ... 2024-08-12 13:11:13 +08:00
blueloveTH
a6adcfd0c1 ... 2024-08-12 12:09:30 +08:00
blueloveTH
3eec499b95 ... 2024-08-12 10:54:30 +08:00
16 changed files with 492 additions and 291 deletions

View File

@ -7,10 +7,7 @@ if ! type -P clang >/dev/null 2>&1; then
exit 1
fi
echo "It takes a moment to finish building."
echo ""
echo "> Running prebuild.py... "
python prebuild.py
if [ $? -ne 0 ]; then
@ -22,23 +19,7 @@ SRC=$(find src/ -name "*.c")
echo "> Compiling and linking source files... "
FLAGS="-std=c11 -O1 -Wfatal-errors -Iinclude -DNDEBUG"
if [[ "$OSTYPE" == "darwin"* ]]; then
LIB_EXTENSION=".dylib"
FLAGS="$FLAGS -undefined dynamic_lookup"
LINK_FLAGS=""
else
LIB_EXTENSION=".so"
LINK_FLAGS="-Wl,-rpath=."
fi
clang $FLAGS -o libpocketpy$LIB_EXTENSION $SRC -fPIC -shared -lm
# compile main.cpp and link to libpocketpy.so
echo "> Compiling main.c and linking to libpocketpy$LIB_EXTENSION..."
clang $FLAGS -o main -O1 src2/main.c -L. -lpocketpy $LINK_FLAGS
clang -std=c11 -O2 -Wfatal-errors -Iinclude -DNDEBUG -o main src2/main.c $SRC -lm
if [ $? -eq 0 ]; then
echo "Build completed. Type \"./main\" to enter REPL."

View File

@ -8,3 +8,5 @@ void pk__add_module_dis();
void pk__add_module_random();
void pk__add_module_json();
void pk__add_module_gc();
void pk__add_module_time();
void pk__add_module_easing();

View File

@ -31,3 +31,4 @@ typedef struct py_TValue {
// 16 bytes to make py_arg() macro work
static_assert(sizeof(py_CFunction) <= 8, "sizeof(py_CFunction) > 8");
static_assert(sizeof(py_TValue) == 16, "sizeof(py_TValue) != 16");
static_assert(offsetof(py_TValue, extra) == 4, "offsetof(py_TValue, extra) != 4");

View File

@ -23,6 +23,7 @@ typedef double py_f64;
typedef void (*py_Dtor)(void*);
#define PY_RAISE // mark a function that can raise an exception
#define PY_RETURN // mark a function that can modify `py_retval()` on success
typedef struct c11_sv {
const char* data;
@ -44,7 +45,7 @@ typedef py_TValue* py_ItemRef;
/// @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.
typedef bool (*py_CFunction)(int argc, py_StackRef argv) PY_RAISE;
typedef bool (*py_CFunction)(int argc, py_StackRef argv) PY_RAISE PY_RETURN;
enum py_CompileMode { EXEC_MODE, EVAL_MODE, SINGLE_MODE };
@ -74,14 +75,16 @@ void py_switchvm(int index);
bool py_exec(const char* source,
const char* filename,
enum py_CompileMode mode,
py_Ref module) PY_RAISE;
py_Ref module) PY_RAISE PY_RETURN;
#define py_eval(source, module) py_exec((source), "<string>", EVAL_MODE, (module))
/// Compile a source string into a code object.
/// Use python's `exec()` or `eval()` to execute it.
bool py_compile(const char* source,
const char* filename,
enum py_CompileMode mode,
bool is_dynamic) PY_RAISE;
bool is_dynamic) PY_RAISE PY_RETURN;
/// Python equivalent to `globals()`.
void py_newglobals(py_Ref);
@ -170,7 +173,7 @@ py_i64 py_toint(py_Ref);
/// Convert a `float` object in python to `double`.
py_f64 py_tofloat(py_Ref);
/// Cast a `int` or `float` object in python to `double`.
/// If successful, returns true and set the value to `out`.
/// If successful, return true and set the value to `out`.
/// Otherwise, return false and raise `TypeError`.
bool py_castfloat(py_Ref, py_f64* out) PY_RAISE;
/// Convert a `bool` object in python to `bool`.
@ -201,6 +204,9 @@ void* py_touserdata(py_Ref);
/// Get the type of the object.
py_Type py_typeof(py_Ref self);
/// Get type by module and name. e.g. `py_gettype("time", py_name("struct_time"))`.
/// Return `0` if not found.
py_Type py_gettype(const char* module, py_Name name);
/// Check if the object is exactly the given type.
bool py_istype(py_Ref, py_Type);
/// Check if the object is an instance of the given type.
@ -223,7 +229,7 @@ py_ItemRef py_tpobject(py_Type type);
/// Get the type name.
const char* py_tpname(py_Type type);
/// Call a type to create a new instance.
bool py_tpcall(py_Type type, int argc, py_Ref argv) PY_RAISE;
bool py_tpcall(py_Type type, int argc, py_Ref argv) PY_RAISE PY_RETURN;
/// Check if the object is an instance of the given type.
/// Raise `TypeError` if the check fails.
@ -276,6 +282,9 @@ void py_setslot(py_Ref self, int i, py_Ref val);
/// Get the current `function` object from the stack.
/// Return `NULL` if not available.
py_StackRef py_inspect_currentfunction();
/// Get the current `module` object where the code is executed.
/// Return `NULL` if not available.
py_GlobalRef py_inspect_currentmodule();
/************* Bindings *************/
@ -315,13 +324,13 @@ void py_bindproperty(py_Type type, const char* name, py_CFunction getter, py_CFu
/************* Python Equivalents *************/
/// Python equivalent to `getattr(self, name)`.
bool py_getattr(py_Ref self, py_Name name) PY_RAISE;
bool py_getattr(py_Ref self, py_Name name) PY_RAISE PY_RETURN;
/// Python equivalent to `setattr(self, name, val)`.
bool py_setattr(py_Ref self, py_Name name, py_Ref val) PY_RAISE;
/// Python equivalent to `delattr(self, name)`.
bool py_delattr(py_Ref self, py_Name name) PY_RAISE;
/// Python equivalent to `self[key]`.
bool py_getitem(py_Ref self, py_Ref key) PY_RAISE;
bool py_getitem(py_Ref self, py_Ref key) PY_RAISE PY_RETURN;
/// Python equivalent to `self[key] = val`.
bool py_setitem(py_Ref self, py_Ref key, py_Ref val) PY_RAISE;
/// Python equivalent to `del self[key]`.
@ -330,7 +339,7 @@ bool py_delitem(py_Ref self, py_Ref key) PY_RAISE;
/// Perform a binary operation.
/// The result will be set to `py_retval()`.
/// The stack remains unchanged after the operation.
bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) PY_RAISE;
bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) PY_RAISE PY_RETURN;
#define py_binaryadd(lhs, rhs) py_binaryop(lhs, rhs, __add__, __radd__)
#define py_binarysub(lhs, rhs) py_binaryop(lhs, rhs, __sub__, __rsub__)
@ -358,6 +367,8 @@ void py_push(py_Ref src);
void py_pushnil();
/// Push a `None` object to the stack.
void py_pushnone();
/// Push a `py_Name` to the stack. This is used for keyword arguments.
void py_pushname(py_Name name);
/// Pop an object from the stack.
void py_pop();
/// Shrink the stack by n.
@ -373,7 +384,10 @@ bool py_pushmethod(py_Name name);
/// Assume `argc + kwargc` arguments are already pushed to the stack.
/// The result will be set to `py_retval()`.
/// The stack size will be reduced by `argc + kwargc`.
bool py_vectorcall(uint16_t argc, uint16_t kwargc) PY_RAISE;
bool py_vectorcall(uint16_t argc, uint16_t kwargc) PY_RAISE PY_RETURN;
/// Evaluate an expression and push the result to the stack.
/// This function is used for testing.
bool py_pusheval(const char* expr, py_GlobalRef module) PY_RAISE;
/************* Modules *************/
@ -428,7 +442,7 @@ bool KeyError(py_Ref key) PY_RAISE;
/// Python equivalent to `bool(val)`.
/// 1: true, 0: false, -1: error
int py_bool(py_Ref val) PY_RAISE;
int py_bool(py_Ref val) PY_RAISE PY_RETURN;
/// Compare two objects.
/// 1: lhs == rhs, 0: lhs != rhs, -1: error
@ -447,34 +461,36 @@ int py_less(py_Ref lhs, py_Ref rhs) PY_RAISE;
/// Get the hash value of the object.
bool py_hash(py_Ref, py_i64* out) PY_RAISE;
/// Get the iterator of the object.
bool py_iter(py_Ref) PY_RAISE;
bool py_iter(py_Ref) PY_RAISE PY_RETURN;
/// Get the next element from the iterator.
/// 1: success, 0: StopIteration, -1: error
int py_next(py_Ref) PY_RAISE;
int py_next(py_Ref) PY_RAISE PY_RETURN;
/// Python equivalent to `lhs is rhs`.
bool py_isidentical(py_Ref, py_Ref);
/// Call a function.
/// It prepares the stack and then performs a `vectorcall(argc, 0, false)`.
/// The result will be set to `py_retval()`.
/// The stack remains unchanged after the operation.
bool py_call(py_Ref f, int argc, py_Ref argv) PY_RAISE;
bool py_call(py_Ref f, int argc, py_Ref argv) PY_RAISE PY_RETURN;
#if PK_DEBUG
/// Call a py_CFunction in a safe way.
/// This function does extra checks to help you debug `py_CFunction`.
bool py_callcfunc(py_CFunction f, int argc, py_Ref argv) PY_RAISE;
bool py_callcfunc(py_CFunction f, int argc, py_Ref argv) PY_RAISE PY_RETURN;
#else
#define py_callcfunc(f, argc, argv) (f((argc), (argv)))
#endif
/// Python equivalent to `str(val)`.
bool py_str(py_Ref val) PY_RAISE;
bool py_str(py_Ref val) PY_RAISE PY_RETURN;
/// Python equivalent to `repr(val)`.
bool py_repr(py_Ref val) PY_RAISE;
bool py_repr(py_Ref val) PY_RAISE PY_RETURN;
/// Python equivalent to `len(val)`.
bool py_len(py_Ref val) PY_RAISE;
bool py_len(py_Ref val) PY_RAISE PY_RETURN;
/// Python equivalent to `json.dumps(val)`.
bool py_json(py_Ref val) PY_RAISE;
bool py_json_dumps(py_Ref val) PY_RAISE PY_RETURN;
/// Python equivalent to `json.loads(val)`.
bool py_json_loads(const char* source) PY_RAISE PY_RETURN;
/************* Unchecked Functions *************/
@ -494,7 +510,7 @@ void py_list_clear(py_Ref self);
void py_list_insert(py_Ref self, int i, py_Ref val);
/// -1: error, 0: not found, 1: found
int py_dict_getitem(py_Ref self, py_Ref key) PY_RAISE;
int py_dict_getitem(py_Ref self, py_Ref key) PY_RAISE PY_RETURN;
/// true: success, false: error
bool py_dict_setitem(py_Ref self, py_Ref key, py_Ref val) PY_RAISE;
/// -1: error, 0: not found, 1: found (and deleted)
@ -511,7 +527,7 @@ int py_dict_len(py_Ref self);
/// An utility function to read a line from stdin for REPL.
int py_replinput(char* buf, int max_size);
/// Python favored string formatting. (just put here, not for users)
/// Python favored string formatting.
/// %d: int
/// %i: py_i64 (int64_t)
/// %f: py_f64 (double)
@ -589,14 +605,3 @@ enum py_PredefinedTypes {
#ifdef __cplusplus
}
#endif
/*
Some notes:
## Macros
1. Function macros are partial functions. They can be used as normal expressions. Use the same
naming convention as functions.
2. Snippet macros are `do {...} while(0)` blocks. They cannot be used as expressions. Use
`UPPER_CASE` naming convention.
3. Constant macros are used for global constants. Use `UPPER_CASE` or k-prefix naming convention.
*/

View File

@ -1,117 +0,0 @@
from typing import Generic, TypeVar
def malloc(size: int) -> 'void_p': ...
def free(ptr: 'void_p') -> None: ...
def memset(ptr: 'void_p', value: int, size: int) -> None: ...
def memcpy(dst: 'void_p', src: 'void_p', size: int) -> None: ...
T = TypeVar('T')
Tp = TypeVar('Tp', bound='void_p')
def p_cast(ptr: 'void_p', cls: type[T]) -> T:
"""Cast a pointer to a specific type."""
def p_value(ptr: 'void_p') -> int:
"""Get the value of a pointer."""
def pp_deref(ptr: Tp) -> Tp:
"""Dereference a double pointer."""
class void_p:
def __init__(self, addr: int): ...
def __eq__(self, other: 'void_p') -> bool: ...
def __ne__(self, other: 'void_p') -> bool: ...
def __lt__(self, other: 'void_p') -> bool: ...
def __le__(self, other: 'void_p') -> bool: ...
def __gt__(self, other: 'void_p') -> bool: ...
def __ge__(self, other: 'void_p') -> bool: ...
def __hash__(self) -> int: ...
def __repr__(self) -> str: ...
class Pointer(Generic[T], void_p):
def read(self) -> T: ...
def write(self, value: T) -> None: ...
def __getitem__(self, index: int) -> T: ...
def __setitem__(self, index: int, value: T) -> None: ...
class char_p(Pointer[int]):
def read_string(self) -> str: ...
def write_string(self, value: str) -> None: ...
class uchar_p(Pointer[int]): pass
class short_p(Pointer[int]): pass
class ushort_p(Pointer[int]): pass
class int_p(Pointer[int]): pass
class uint_p(Pointer[int]): pass
class long_p(Pointer[int]): pass
class ulong_p(Pointer[int]): pass
class longlong_p(Pointer[int]): pass
class ulonglong_p(Pointer[int]): pass
class float_p(Pointer[float]): pass
class double_p(Pointer[float]): pass
class bool_p(Pointer[bool]): pass
class struct:
def __init__(self, size: int): ...
def addr(self) -> 'void_p': ...
def copy(self) -> 'struct': ...
def sizeof(self) -> int: ...
def __eq__(self, other: 'struct') -> bool: ...
def __ne__(self, other: 'struct') -> bool: ...
def hex(self) -> str: ...
@staticmethod
def fromhex(s: str) -> 'struct': ...
def read_char(self, offset=0) -> int: ...
def read_uchar(self, offset=0) -> int: ...
def read_short(self, offset=0) -> int: ...
def read_ushort(self, offset=0) -> int: ...
def read_int(self, offset=0) -> int: ...
def read_uint(self, offset=0) -> int: ...
def read_long(self, offset=0) -> int: ...
def read_ulong(self, offset=0) -> int: ...
def read_longlong(self, offset=0) -> int: ...
def read_ulonglong(self, offset=0) -> int: ...
def read_float(self, offset=0) -> float: ...
def read_double(self, offset=0) -> float: ...
def read_bool(self, offset=0) -> bool: ...
def read_void_p(self, offset=0) -> 'void_p': ...
def write_char(self, value: int, offset=0) -> None: ...
def write_uchar(self, value: int, offset=0) -> None: ...
def write_short(self, value: int, offset=0) -> None: ...
def write_ushort(self, value: int, offset=0) -> None: ...
def write_int(self, value: int, offset=0) -> None: ...
def write_uint(self, value: int, offset=0) -> None: ...
def write_long(self, value: int, offset=0) -> None: ...
def write_ulong(self, value: int, offset=0) -> None: ...
def write_longlong(self, value: int, offset=0) -> None: ...
def write_ulonglong(self, value: int, offset=0) -> None: ...
def write_float(self, value: float, offset=0) -> None: ...
def write_double(self, value: float, offset=0) -> None: ...
def write_bool(self, value: bool, offset=0) -> None: ...
def write_void_p(self, value: 'void_p', offset=0) -> None: ...
def char_(val: int) -> struct: ...
def uchar_(val: int) -> struct: ...
def short_(val: int) -> struct: ...
def ushort_(val: int) -> struct: ...
def int_(val: int) -> struct: ...
def uint_(val: int) -> struct: ...
def long_(val: int) -> struct: ...
def ulong_(val: int) -> struct: ...
def longlong_(val: int) -> struct: ...
def ulonglong_(val: int) -> struct: ...
def float_(val: float) -> struct: ...
def double_(val: float) -> struct: ...
def bool_(val: bool) -> struct: ...
class _StructLike(Generic[T]):
def tostruct(self) -> struct: ...
@classmethod
def fromstruct(cls, s: struct) -> T: ...
def addr(self) -> 'Pointer[T]': ...
def copy(self) -> T: ...
def sizeof(self) -> int: ...
def __eq__(self, other: T) -> bool: ...
def __ne__(self, other: T) -> bool: ...

View File

@ -1,4 +1,5 @@
from time import localtime
import operator
class timedelta:
def __init__(self, days=0, seconds=0):
@ -13,25 +14,10 @@ class timedelta:
return NotImplemented
return (self.days, self.seconds) == (other.days, other.seconds)
def __lt__(self, other: 'timedelta') -> bool:
def __ne__(self, other: 'timedelta') -> bool:
if type(other) is not timedelta:
return NotImplemented
return (self.days, self.seconds) < (other.days, other.seconds)
def __le__(self, other: 'timedelta') -> bool:
if type(other) is not timedelta:
return NotImplemented
return (self.days, self.seconds) <= (other.days, other.seconds)
def __gt__(self, other: 'timedelta') -> bool:
if type(other) is not timedelta:
return NotImplemented
return (self.days, self.seconds) > (other.days, other.seconds)
def __ge__(self, other: 'timedelta') -> bool:
if type(other) is not timedelta:
return NotImplemented
return (self.days, self.seconds) >= (other.days, other.seconds)
return (self.days, self.seconds) != (other.days, other.seconds)
class date:
@ -45,30 +31,32 @@ class date:
t = localtime()
return date(t.tm_year, t.tm_mon, t.tm_mday)
def __eq__(self, other: 'date') -> bool:
if type(other) is not date:
def __cmp(self, other, op):
if not isinstance(other, date):
return NotImplemented
return (self.year, self.month, self.day) == (other.year, other.month, other.day)
if self.year != other.year:
return op(self.year, other.year)
if self.month != other.month:
return op(self.month, other.month)
return op(self.day, other.day)
def __eq__(self, other: 'date') -> bool:
return self.__cmp(other, operator.eq)
def __ne__(self, other: 'date') -> bool:
return self.__cmp(other, operator.ne)
def __lt__(self, other: 'date') -> bool:
if type(other) is not date:
return NotImplemented
return (self.year, self.month, self.day) < (other.year, other.month, other.day)
return self.__cmp(other, operator.lt)
def __le__(self, other: 'date') -> bool:
if type(other) is not date:
return NotImplemented
return (self.year, self.month, self.day) <= (other.year, other.month, other.day)
return self.__cmp(other, operator.le)
def __gt__(self, other: 'date') -> bool:
if type(other) is not date:
return NotImplemented
return (self.year, self.month, self.day) > (other.year, other.month, other.day)
return self.__cmp(other, operator.gt)
def __ge__(self, other: 'date') -> bool:
if type(other) is not date:
return NotImplemented
return (self.year, self.month, self.day) >= (other.year, other.month, other.day)
return self.__cmp(other, operator.ge)
def __str__(self):
return f"{self.year}-{self.month:02}-{self.day:02}"
@ -108,41 +96,37 @@ class datetime(date):
def __repr__(self):
return f"datetime.datetime({self.year}, {self.month}, {self.day}, {self.hour}, {self.minute}, {self.second})"
def __eq__(self, other) -> bool:
if type(other) is not datetime:
def __cmp(self, other, op):
if not isinstance(other, datetime):
return NotImplemented
return (self.year, self.month, self.day, self.hour, self.minute, self.second) ==\
(other.year, other.month, other.day,
other.hour, other.minute, other.second)
if self.year != other.year:
return op(self.year, other.year)
if self.month != other.month:
return op(self.month, other.month)
if self.day != other.day:
return op(self.day, other.day)
if self.hour != other.hour:
return op(self.hour, other.hour)
if self.minute != other.minute:
return op(self.minute, other.minute)
return op(self.second, other.second)
def __eq__(self, other) -> bool:
return self.__cmp(other, operator.eq)
def __ne__(self, other) -> bool:
return self.__cmp(other, operator.ne)
def __lt__(self, other) -> bool:
if type(other) is not datetime:
return NotImplemented
return (self.year, self.month, self.day, self.hour, self.minute, self.second) <\
(other.year, other.month, other.day,
other.hour, other.minute, other.second)
return self.__cmp(other, operator.lt)
def __le__(self, other) -> bool:
if type(other) is not datetime:
return NotImplemented
return (self.year, self.month, self.day, self.hour, self.minute, self.second) <=\
(other.year, other.month, other.day,
other.hour, other.minute, other.second)
return self.__cmp(other, operator.le)
def __gt__(self, other) -> bool:
if type(other) is not datetime:
return NotImplemented
return (self.year, self.month, self.day, self.hour, self.minute, self.second) >\
(other.year, other.month, other.day,
other.hour, other.minute, other.second)
return self.__cmp(other, operator.gt)
def __ge__(self, other) -> bool:
if type(other) is not datetime:
return NotImplemented
return (self.year, self.month, self.day, self.hour, self.minute, self.second) >=\
(other.year, other.month, other.day,
other.hour, other.minute, other.second)
return self.__cmp(other, operator.ge)
def timestamp(self) -> float:
raise NotImplementedError

File diff suppressed because one or more lines are too long

View File

@ -202,6 +202,8 @@ void VM__ctor(VM* self) {
pk__add_module_random();
pk__add_module_json();
pk__add_module_gc();
pk__add_module_time();
pk__add_module_easing();
// add python builtins
do {
@ -329,7 +331,9 @@ py_Type pk_newtype(const char* name,
}
py_Type py_newtype(const char* name, py_Type base, const py_GlobalRef module, void (*dtor)(void*)) {
return pk_newtype(name, base, module, dtor, false, false);
py_Type type = pk_newtype(name, base, module, dtor, false, false);
if(module) py_setdict(module, py_name(name), py_tpobject(type));
return type;
}
static bool

251
src/modules/easing.c Normal file
View File

@ -0,0 +1,251 @@
#include "pocketpy/pocketpy.h"
#include "pocketpy/interpreter/vm.h"
#include "math.h"
// https://easings.net/
const double kPi = 3.1415926545;
static double easeLinear(double x) { return x; }
static double easeInSine(double x) { return 1.0 - cos(x * kPi / 2); }
static double easeOutSine(double x) { return sin(x * kPi / 2); }
static double easeInOutSine(double x) { return -(cos(kPi * x) - 1) / 2; }
static double easeInQuad(double x) { return x * x; }
static double easeOutQuad(double x) { return 1 - pow(1 - x, 2); }
static double easeInOutQuad(double x) {
if(x < 0.5) {
return 2 * x * x;
} else {
return 1 - pow(-2 * x + 2, 2) / 2;
}
}
static double easeInCubic(double x) { return x * x * x; }
static double easeOutCubic(double x) { return 1 - pow(1 - x, 3); }
static double easeInOutCubic(double x) {
if(x < 0.5) {
return 4 * x * x * x;
} else {
return 1 - pow(-2 * x + 2, 3) / 2;
}
}
static double easeInQuart(double x) { return pow(x, 4); }
static double easeOutQuart(double x) { return 1 - pow(1 - x, 4); }
static double easeInOutQuart(double x) {
if(x < 0.5) {
return 8 * pow(x, 4);
} else {
return 1 - pow(-2 * x + 2, 4) / 2;
}
}
static double easeInQuint(double x) { return pow(x, 5); }
static double easeOutQuint(double x) { return 1 - pow(1 - x, 5); }
static double easeInOutQuint(double x) {
if(x < 0.5) {
return 16 * pow(x, 5);
} else {
return 1 - pow(-2 * x + 2, 5) / 2;
}
}
static double easeInExpo(double x) { return x == 0 ? 0 : pow(2, 10 * x - 10); }
static double easeOutExpo(double x) { return x == 1 ? 1 : 1 - pow(2, -10 * x); }
static double easeInOutExpo(double x) {
if(x == 0) {
return 0;
} else if(x == 1) {
return 1;
} else if(x < 0.5) {
return pow(2, 20 * x - 10) / 2;
} else {
return (2 - pow(2, -20 * x + 10)) / 2;
}
}
static double easeInCirc(double x) { return 1 - sqrt(1 - pow(x, 2)); }
static double easeOutCirc(double x) { return sqrt(1 - pow(x - 1, 2)); }
static double easeInOutCirc(double x) {
if(x < 0.5) {
return (1 - sqrt(1 - pow(2 * x, 2))) / 2;
} else {
return (sqrt(1 - pow(-2 * x + 2, 2)) + 1) / 2;
}
}
static double easeInBack(double x) {
const double c1 = 1.70158;
const double c3 = c1 + 1;
return c3 * x * x * x - c1 * x * x;
}
static double easeOutBack(double x) {
const double c1 = 1.70158;
const double c3 = c1 + 1;
return 1 + c3 * pow(x - 1, 3) + c1 * pow(x - 1, 2);
}
static double easeInOutBack(double x) {
const double c1 = 1.70158;
const double c2 = c1 * 1.525;
if(x < 0.5) {
return (pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2)) / 2;
} else {
return (pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2;
}
}
static double easeInElastic(double x) {
const double c4 = (2 * kPi) / 3;
if(x == 0) {
return 0;
} else if(x == 1) {
return 1;
} else {
return -pow(2, 10 * x - 10) * sin((x * 10 - 10.75) * c4);
}
}
static double easeOutElastic(double x) {
const double c4 = (2 * kPi) / 3;
if(x == 0) {
return 0;
} else if(x == 1) {
return 1;
} else {
return pow(2, -10 * x) * sin((x * 10 - 0.75) * c4) + 1;
}
}
static double easeInOutElastic(double x) {
const double c5 = (2 * kPi) / 4.5;
if(x == 0) {
return 0;
} else if(x == 1) {
return 1;
} else if(x < 0.5) {
return -(pow(2, 20 * x - 10) * sin((20 * x - 11.125) * c5)) / 2;
} else {
return (pow(2, -20 * x + 10) * sin((20 * x - 11.125) * c5)) / 2 + 1;
}
}
static double easeOutBounce(double x) {
const double n1 = 7.5625;
const double d1 = 2.75;
if(x < 1 / d1) {
return n1 * x * x;
} else if(x < 2 / d1) {
x -= 1.5 / d1;
return n1 * x * x + 0.75;
} else if(x < 2.5 / d1) {
x -= 2.25 / d1;
return n1 * x * x + 0.9375;
} else {
x -= 2.625 / d1;
return n1 * x * x + 0.984375;
}
}
static double easeInBounce(double x) { return 1 - easeOutBounce(1 - x); }
static double easeInOutBounce(double x) {
return x < 0.5 ? (1 - easeOutBounce(1 - 2 * x)) / 2 : (1 + easeOutBounce(2 * x - 1)) / 2;
}
#define DEF_EASE(name) \
static bool easing_##name(int argc, py_Ref argv) { \
PY_CHECK_ARGC(1); \
py_f64 t; \
if(!py_castfloat(argv, &t)) return false; \
py_newfloat(py_retval(), ease##name(t)); \
return true; \
}
DEF_EASE(Linear)
DEF_EASE(InSine)
DEF_EASE(OutSine)
DEF_EASE(InOutSine)
DEF_EASE(InQuad)
DEF_EASE(OutQuad)
DEF_EASE(InOutQuad)
DEF_EASE(InCubic)
DEF_EASE(OutCubic)
DEF_EASE(InOutCubic)
DEF_EASE(InQuart)
DEF_EASE(OutQuart)
DEF_EASE(InOutQuart)
DEF_EASE(InQuint)
DEF_EASE(OutQuint)
DEF_EASE(InOutQuint)
DEF_EASE(InExpo)
DEF_EASE(OutExpo)
DEF_EASE(InOutExpo)
DEF_EASE(InCirc)
DEF_EASE(OutCirc)
DEF_EASE(InOutCirc)
DEF_EASE(InBack)
DEF_EASE(OutBack)
DEF_EASE(InOutBack)
DEF_EASE(InElastic)
DEF_EASE(OutElastic)
DEF_EASE(InOutElastic)
DEF_EASE(InBounce)
DEF_EASE(OutBounce)
DEF_EASE(InOutBounce)
#undef DEF_EASE
void pk__add_module_easing() {
py_GlobalRef mod = py_newmodule("easing");
py_bindfunc(mod, "Linear", easing_Linear);
py_bindfunc(mod, "InSine", easing_InSine);
py_bindfunc(mod, "OutSine", easing_OutSine);
py_bindfunc(mod, "InOutSine", easing_InOutSine);
py_bindfunc(mod, "InQuad", easing_InQuad);
py_bindfunc(mod, "OutQuad", easing_OutQuad);
py_bindfunc(mod, "InOutQuad", easing_InOutQuad);
py_bindfunc(mod, "InCubic", easing_InCubic);
py_bindfunc(mod, "OutCubic", easing_OutCubic);
py_bindfunc(mod, "InOutCubic", easing_InOutCubic);
py_bindfunc(mod, "InQuart", easing_InQuart);
py_bindfunc(mod, "OutQuart", easing_OutQuart);
py_bindfunc(mod, "InOutQuart", easing_InOutQuart);
py_bindfunc(mod, "InQuint", easing_InQuint);
py_bindfunc(mod, "OutQuint", easing_OutQuint);
py_bindfunc(mod, "InOutQuint", easing_InOutQuint);
py_bindfunc(mod, "InExpo", easing_InExpo);
py_bindfunc(mod, "OutExpo", easing_OutExpo);
py_bindfunc(mod, "InOutExpo", easing_InOutExpo);
py_bindfunc(mod, "InCirc", easing_InCirc);
py_bindfunc(mod, "OutCirc", easing_OutCirc);
py_bindfunc(mod, "InOutCirc", easing_InOutCirc);
py_bindfunc(mod, "InBack", easing_InBack);
py_bindfunc(mod, "OutBack", easing_OutBack);
py_bindfunc(mod, "InOutBack", easing_InOutBack);
py_bindfunc(mod, "InElastic", easing_InElastic);
py_bindfunc(mod, "OutElastic", easing_OutElastic);
py_bindfunc(mod, "InOutElastic", easing_InOutElastic);
py_bindfunc(mod, "InBounce", easing_InBounce);
py_bindfunc(mod, "OutBounce", easing_OutBounce);
py_bindfunc(mod, "InOutBounce", easing_InOutBounce);
}

View File

@ -10,13 +10,12 @@ static bool json_loads(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
PY_CHECK_ARG_TYPE(0, tp_str);
const char* source = py_tostr(argv);
py_GlobalRef mod = py_getmodule("json");
return py_exec(source, "<json>", EVAL_MODE, mod);
return py_json_loads(source);
}
static bool json_dumps(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
return py_json(argv);
return py_json_dumps(argv);
}
void pk__add_module_json() {
@ -98,14 +97,26 @@ static bool json__write_object(c11_sbuf* buf, py_TValue* obj) {
}
}
bool py_json(py_Ref val) {
bool py_json_dumps(py_Ref val) {
c11_sbuf buf;
c11_sbuf__ctor(&buf);
bool ok = json__write_object(&buf, val);
if(!ok){
if(!ok) {
c11_sbuf__dtor(&buf);
return false;
}
c11_sbuf__py_submit(&buf, py_retval());
return true;
}
bool py_json_loads(const char* source) {
py_GlobalRef mod = py_getmodule("json");
return py_exec(source, "<json>", EVAL_MODE, mod);
}
bool py_pusheval(const char* expr, py_GlobalRef module) {
bool ok = py_exec(expr, "<string>", EVAL_MODE, module);
if(!ok) return false;
py_push(py_retval());
return true;
}

103
src/modules/time.c Normal file
View File

@ -0,0 +1,103 @@
#include "pocketpy/pocketpy.h"
#include "pocketpy/interpreter/vm.h"
#include "time.h"
#define NANOS_PER_SEC 1000000000
static bool get_ns(int64_t* out) {
struct timespec tms;
/* The C11 way */
if(!timespec_get(&tms, TIME_UTC)) {
return py_exception(tp_OSError, "%s", "timespec_get() failed");
}
/* seconds, multiplied with 1 billion */
int64_t nanos = tms.tv_sec * NANOS_PER_SEC;
/* Add full nanoseconds */
nanos += tms.tv_nsec;
*out = nanos;
return true;
}
static bool time_time(int argc, py_Ref argv) {
PY_CHECK_ARGC(0);
int64_t nanos;
if(!get_ns(&nanos)) return false;
py_newfloat(py_retval(), (double)nanos / NANOS_PER_SEC);
return true;
}
static bool time_time_ns(int argc, py_Ref argv) {
PY_CHECK_ARGC(0);
int64_t nanos;
if(!get_ns(&nanos)) return false;
py_newint(py_retval(), nanos);
return true;
}
static bool time_sleep(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
py_f64 secs;
if(!py_castfloat(argv, &secs)) return false;
int64_t start;
if(!get_ns(&start)) return false;
const int64_t end = start + secs * 1000000000;
while(true) {
int64_t now;
if(!get_ns(&now)) return false;
if(now >= end) break;
}
py_newnone(py_retval());
return true;
}
static bool time_localtime(int argc, py_Ref argv) {
PY_CHECK_ARGC(0);
py_Type tp_struct_time = py_gettype("time", py_name("struct_time"));
assert(tp_struct_time);
struct tm* ud = py_newobject(py_retval(), tp_struct_time, 0, sizeof(struct tm));
time_t t = time(NULL);
*ud = *localtime(&t);
return true;
}
#define DEF_STRUCT_TIME__PROPERTY(name, expr) \
static bool struct_time__##name(int argc, py_Ref argv) { \
PY_CHECK_ARGC(1); \
struct tm* tm = py_touserdata(argv); \
py_newint(py_retval(), expr); \
return true; \
}
DEF_STRUCT_TIME__PROPERTY(tm_year, tm->tm_year + 1900)
DEF_STRUCT_TIME__PROPERTY(tm_mon, tm->tm_mon + 1)
DEF_STRUCT_TIME__PROPERTY(tm_mday, tm->tm_mday)
DEF_STRUCT_TIME__PROPERTY(tm_hour, tm->tm_hour)
DEF_STRUCT_TIME__PROPERTY(tm_min, tm->tm_min)
DEF_STRUCT_TIME__PROPERTY(tm_sec, tm->tm_sec)
DEF_STRUCT_TIME__PROPERTY(tm_wday, (tm->tm_wday + 6) % 7)
DEF_STRUCT_TIME__PROPERTY(tm_yday, tm->tm_yday + 1)
DEF_STRUCT_TIME__PROPERTY(tm_isdst, tm->tm_isdst)
#undef DEF_STRUCT_TIME__PROPERTY
void pk__add_module_time() {
py_Ref mod = py_newmodule("time");
py_Type tp_struct_time = py_newtype("struct_time", tp_object, mod, NULL);
py_bindproperty(tp_struct_time, "tm_year", struct_time__tm_year, NULL);
py_bindproperty(tp_struct_time, "tm_mon", struct_time__tm_mon, NULL);
py_bindproperty(tp_struct_time, "tm_mday", struct_time__tm_mday, NULL);
py_bindproperty(tp_struct_time, "tm_hour", struct_time__tm_hour, NULL);
py_bindproperty(tp_struct_time, "tm_min", struct_time__tm_min, NULL);
py_bindproperty(tp_struct_time, "tm_sec", struct_time__tm_sec, NULL);
py_bindproperty(tp_struct_time, "tm_wday", struct_time__tm_wday, NULL);
py_bindproperty(tp_struct_time, "tm_yday", struct_time__tm_yday, NULL);
py_bindproperty(tp_struct_time, "tm_isdst", struct_time__tm_isdst, NULL);
py_bindfunc(mod, "time", time_time);
py_bindfunc(mod, "time_ns", time_time_ns);
py_bindfunc(mod, "sleep", time_sleep);
py_bindfunc(mod, "localtime", time_localtime);
}

View File

@ -58,3 +58,11 @@ bool py_issubclass(py_Type derived, py_Type base) {
}
py_Type py_typeof(py_Ref self) { return self->type; }
py_Type py_gettype(const char* module, py_Name name) {
py_Ref mod = py_getmodule(module);
if(!mod) return 0;
py_Ref object = py_getdict(mod, name);
if(object && py_istype(object, tp_type)) return py_totype(object);
return 0;
}

View File

@ -21,9 +21,6 @@ py_Ref py_getdict(py_Ref self, py_Name name) {
void py_setdict(py_Ref self, py_Name name, py_Ref val) {
assert(self && self->is_ptr);
// if(py_isidentical(self, &pk_current_vm->main)){
// printf("Setting main: %s\n", py_name2str(name));
// }
if(!py_ismagicname(name) || self->type != tp_type) {
NameDict__set(PyObject__dict(self->_obj), name, *val);
} else {
@ -67,6 +64,12 @@ py_StackRef py_inspect_currentfunction(){
return frame->p0;
}
py_GlobalRef py_inspect_currentmodule(){
Frame* frame = pk_current_vm->top_frame;
if(!frame) return NULL;
return frame->module;
}
void py_assign(py_Ref dst, py_Ref src) { *dst = *src; }
/* Stack References */
@ -100,8 +103,12 @@ void py_pushnone() {
py_newnone(vm->stack.sp++);
}
void py_pushname(py_Name name){
VM* vm = pk_current_vm;
py_newint(vm->stack.sp++, name);
}
py_Ref py_pushtmp() {
VM* vm = pk_current_vm;
py_newnil(vm->stack.sp++);
return py_peek(-1);
return vm->stack.sp++;
}

View File

@ -4,11 +4,6 @@ import datetime
def test_timedelta():
assert datetime.timedelta(days=1) == datetime.timedelta(days=1)
assert datetime.timedelta(days=1) != datetime.timedelta(days=2)
assert datetime.timedelta(days=1, seconds=1) >= datetime.timedelta(days=1)
assert datetime.timedelta(days=0, seconds=1) <= datetime.timedelta(days=1)
assert datetime.timedelta(days=1, seconds=1) < datetime.timedelta(days=2)
assert datetime.timedelta(days=1, seconds=1) > datetime.timedelta(days=0)
def test_date():
assert datetime.date(2023, 8, 5) == datetime.date(2023, 8, 5)
@ -18,7 +13,6 @@ def test_date():
assert datetime.date(2024, 8, 5) > datetime.date(2023, 8, 6)
assert datetime.date(2023, 8, 5) < datetime.date(2024, 8, 6)
def test_datetime():
assert datetime.datetime(
2023, 8, 5, 12, 0, 0) == datetime.datetime(2023, 8, 5, 12, 0, 0)
@ -33,7 +27,6 @@ def test_datetime():
assert datetime.datetime(
2023, 8, 5, 12, 0, 0) <= datetime.datetime(2023, 8, 5, 12, 1, 0)
test_timedelta()
test_date()
test_datetime()

View File

@ -1,4 +1,4 @@
from linalg import mat3x3, vec2, vec3, vec4
from linalg import mat3x3, vec2, vec3
import random
import sys
import math
@ -69,25 +69,6 @@ element_value_list = [getattr(test_vec3, attr) for attr in element_name_list]
copy_element_value_list = [getattr(test_vec3, attr) for attr in element_name_list]
assert element_value_list == copy_element_value_list
# test vec4--------------------------------------------------------------------
# 生成随机测试目标
min_num = -10.0
max_num = 10.0
test_vec4 = vec4(*tuple([random.uniform(min_num, max_num) for _ in range(4)]))
static_test_vec4_float = vec4(3.1886954323, -1098399.59932453432, 9.00000000000002765, 4565400000000.0000000045)
static_test_vec4_int = vec4(278, -13919730938747, 1364223456756456, -37)
# test __repr__
assert str(static_test_vec4_float).startswith('vec4(')
assert str(static_test_vec4_int).startswith('vec4(')
# test copy
element_name_list = ['x', 'y', 'z', 'w']
element_value_list = [getattr(test_vec4, attr) for attr in element_name_list]
copy_element_value_list = [getattr(test_vec4.copy(), attr) for attr in element_name_list]
assert element_value_list == copy_element_value_list
# test mat3x3--------------------------------------------------------------------
def mat_to_str_list(mat):
ret = [[0,0,0], [0,0,0], [0,0,0]]
@ -446,13 +427,6 @@ assert test_mat_copy.inverse_transform_point(test_vec2_copy) == test_mat_copy.in
# test inverse_transform_vector
assert test_mat_copy.inverse_transform_vector(test_vec2_copy) == test_mat_copy.inverse().transform_vector(test_vec2_copy)
import c
a = vec4(1, 2, 3, 4)
b = a.tostruct()
assert a.sizeof() == 16
assert b.sizeof() == 16
assert vec4.fromstruct(b) == a
val = vec2.angle(vec2(-1, 0), vec2(0, -1))
assert 1.57 < val < 1.58
@ -466,12 +440,6 @@ class mymat3x3(mat3x3):
assert mymat3x3().f()
# test assign
c = vec4(1, 2, 3, 4)
assert c.copy_(vec4(5, 6, 7, 8)) is None
assert c == vec4(5, 6, 7, 8)
d = mat3x3.identity()
assert d.copy_(mat3x3.zeros()) is None
assert d == mat3x3.zeros()
@ -491,9 +459,7 @@ except IndexError:
# test vec * vec
assert vec2(1, 2) * vec2(3, 4) == vec2(3, 8)
assert vec3(1, 2, 3) * vec3(4, 5, 6) == vec3(4, 10, 18)
assert vec4(1, 2, 3, 4) * vec4(5, 6, 7, 8) == vec4(5, 12, 21, 32)
# test vec.__getitem__
assert vec2(1, 2)[0] == 1 and vec2(1, 2)[1] == 2
assert vec3(1, 2, 3)[0] == 1 and vec3(1, 2, 3)[1] == 2 and vec3(1, 2, 3)[2] == 3
assert vec4(1, 2, 3, 4)[0] == 1 and vec4(1, 2, 3, 4)[1] == 2 and vec4(1, 2, 3, 4)[2] == 3 and vec4(1, 2, 3, 4)[3] == 4

View File

@ -259,14 +259,15 @@ DEALINGS IN THE SOFTWARE.
var Module = {
onRuntimeInitialized: function () {
Module.ccall('py_initialize', null, [], []);
console.log("py_initialize() called");
},
print: function (text) {
console.log(text);
code_output.innerText += text + '\n';
},
onabort: function (what) {
code_output.innerText += 'Aborted: ' + what + '\n';
Module.ccall('py_finalize', null, [], []);
console.log("py_finalize() called");
}
};
</script>
@ -294,6 +295,7 @@ DEALINGS IN THE SOFTWARE.
'py_exec', 'boolean', ['string', 'string', 'number', 'number'],
[source, 'main.py', 0, 0]
);
console.log("py_exec() called");
if (!ok) {
Module.ccall('py_printexc', null, [], []);
Module.ccall('py_clearexc', null, ['number'], [0]);