Compare commits

...

13 Commits

Author SHA1 Message Date
blueloveTH
8264f125d6 ... 2024-08-06 15:25:26 +08:00
blueloveTH
b6993532fa ... 2024-08-06 14:12:55 +08:00
blueloveTH
1c1e898950 ... 2024-08-06 14:10:46 +08:00
blueloveTH
6805b418b5 ... 2024-08-06 14:00:59 +08:00
blueloveTH
3a2e8ab6c5 ... 2024-08-06 13:56:56 +08:00
blueloveTH
c4f761d7c2 ... 2024-08-06 13:53:34 +08:00
blueloveTH
e94cfaf42e Delete run_c_binding_test.sh 2024-08-06 13:51:25 +08:00
blueloveTH
749435e516 ... 2024-08-06 13:47:41 +08:00
blueloveTH
f756bd813d ... 2024-08-06 13:31:41 +08:00
blueloveTH
bf5fe3d898 ... 2024-08-06 13:15:50 +08:00
blueloveTH
f9a1bd1d49 ... 2024-08-06 12:58:11 +08:00
blueloveTH
0bd25e7224 ... 2024-08-06 12:54:20 +08:00
blueloveTH
ceb49d832b add bytes 2024-08-06 12:46:16 +08:00
51 changed files with 419 additions and 776 deletions

View File

@ -1,3 +1,5 @@
set -e
# if no $1 default arm64-v8a
if [ -z $1 ]; then
$1=arm64-v8a

View File

@ -1,3 +1,5 @@
set -e
rm -rf build
mkdir build
cd build

View File

@ -1,10 +1,10 @@
set -e
python prebuild.py
rm -rf web/lib
mkdir web/lib
SRC_C=$(find src/ -name "*.c")
SRC_CPP=$(find src/ -name "*.cpp")
SRC="$SRC_C $SRC_CPP"
SRC=$(find src/ -name "*.c")
em++ $SRC -Iinclude/ -fexceptions -frtti -s -Os -sEXPORTED_FUNCTIONS=_pkpy_new_repl,_pkpy_repl_input,_pkpy_new_vm -sEXPORTED_RUNTIME_METHODS=ccall -o web/lib/pocketpy.js
emcc $SRC -Iinclude/ -s -Os -sEXPORTED_FUNCTIONS=_py_initialize,_py_finalize,_py_exec,_py_replinput -sEXPORTED_RUNTIME_METHODS=ccall -o web/lib/pocketpy.js

View File

@ -1,20 +1,14 @@
#pragma once
// generated by prebuild.py
#ifdef __cplusplus
extern "C" {
#endif
const char* load_kPythonLib(const char* name);
extern const char kPythonLibs__enum[];
extern const char kPythonLibs__long[];
extern const char kPythonLibs__set[];
extern const char kPythonLibs_bisect[];
extern const char kPythonLibs_builtins[];
extern const char kPythonLibs_cmath[];
extern const char kPythonLibs_collections[];
extern const char kPythonLibs_colorsys[];
extern const char kPythonLibs_datetime[];
extern const char kPythonLibs_functools[];
extern const char kPythonLibs_heapq[];
@ -23,7 +17,3 @@ extern const char kPythonLibs_operator[];
extern const char kPythonLibs_pickle[];
extern const char kPythonLibs_this[];
extern const char kPythonLibs_typing[];
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -2,10 +2,6 @@
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
#define c11__less(a, b) ((a) < (b))
#define c11__lower_bound(T, ptr, count, key, less, out_index) \
@ -42,8 +38,3 @@ bool c11__stable_sort(void* ptr,
int elem_size,
int (*f_lt)(const void* a, const void* b, void* extra),
void* extra);
#ifdef __cplusplus
}
#endif

View File

@ -1,9 +1,5 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#define kPoolExprBlockSize 128
#define kPoolFrameBlockSize 80
#define kPoolObjectBlockSize 80
@ -24,8 +20,3 @@ void PoolObject_dealloc(void* p);
void PoolObject_shrink_to_fit();
void Pools_debug_info(char* buffer, int size);
#ifdef __cplusplus
}
#endif

View File

@ -4,10 +4,6 @@
#include "pocketpy/common/str.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define SMALLMAP_T__HEADER
#define K uint16_t
#define V int
@ -24,7 +20,3 @@ extern "C" {
#define equal(a, b) (c11_sv__cmp((a), (b)) == 0)
#include "pocketpy/xmacros/smallmap.h"
#undef SMALLMAP_T__HEADER
#ifdef __cplusplus
}
#endif

View File

@ -6,10 +6,6 @@
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct c11_sbuf {
c11_vector data;
} c11_sbuf;
@ -34,7 +30,3 @@ void c11_sbuf__py_submit(c11_sbuf* self, py_Ref out);
void pk_vsprintf(c11_sbuf* ss, const char* fmt, va_list args);
void pk_sprintf(c11_sbuf* ss, const char* fmt, ...);
#ifdef __cplusplus
}
#endif

View File

@ -4,10 +4,6 @@
#include "pocketpy/common/utils.h"
#include "pocketpy/pocketpy.h"
#ifdef __cplusplus
extern "C" {
#endif
/* string */
typedef struct c11_string{
// int size | char[] | '\0'
@ -21,6 +17,8 @@ typedef struct c11_bytes{
unsigned char data[]; // flexible array member
} c11_bytes;
bool c11_bytes__eq(c11_bytes* self, c11_bytes* other);
int c11_sv__cmp(c11_sv self, c11_sv other);
int c11_sv__cmp2(c11_sv self, const char* other);
@ -72,7 +70,3 @@ typedef enum IntParsingResult{
} IntParsingResult;
IntParsingResult c11__parse_uint(c11_sv text, int64_t* out, int base);
#ifdef __cplusplus
}
#endif

View File

@ -3,13 +3,5 @@
#include <stdint.h>
#include "pocketpy/common/str.h"
#ifdef __cplusplus
extern "C" {
#endif
void py_Name__initialize();
void py_Name__finalize();
#ifdef __cplusplus
}
#endif

View File

@ -3,10 +3,6 @@
#include "stdio.h"
#include "stdlib.h"
#ifdef __cplusplus
extern "C" {
#endif
#define PK_REGION(name) 1
#define PK_SLICE_LOOP(i, start, stop, step) \
@ -52,7 +48,3 @@ typedef struct RefCounted {
free(obj); \
} \
} while(0)
#ifdef __cplusplus
}
#endif

View File

@ -7,10 +7,6 @@
#include <stdbool.h>
#include <assert.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct c11_array {
void* data;
int count;
@ -92,7 +88,3 @@ c11_array c11_vector__submit(c11_vector* self);
// NOTE: here we do an extra NULL check for it to avoid UB
#define c11__foreach(T, self, it) \
for(T* it = (self)->data; it && it != (T*)(self)->data + (self)->count; it++)
#ifdef __cplusplus
}
#endif

View File

@ -5,12 +5,4 @@
#include "pocketpy/objects/sourcedata.h"
#include "pocketpy/objects/codeobject.h"
#ifdef __cplusplus
extern "C" {
#endif
Error* pk_compile(SourceData_ src, CodeObject* out);
#ifdef __cplusplus
}
#endif

View File

@ -6,10 +6,6 @@
#include "pocketpy/objects/error.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
extern const char* TokenSymbols[];
typedef enum TokenIndex{
@ -95,7 +91,3 @@ Error* Lexer__process_and_dump(SourceData_ src, c11_string** out_string);
void TokenArray__dtor(TokenArray* self);
#define Token__sv(self) (c11_sv){(self)->start, (self)->length}
#ifdef __cplusplus
}
#endif

View File

@ -6,10 +6,7 @@
#include "pocketpy/objects/object.h"
#include "pocketpy/common/config.h"
#include "pocketpy/common/strname.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "pocketpy/pocketpy.h"
py_TValue* FastLocals__try_get_by_name(py_TValue* locals, const CodeObject* co, py_Name name);
NameDict* FastLocals__to_namedict(py_TValue* locals, const CodeObject* co);
@ -38,7 +35,7 @@ typedef struct Frame {
struct Frame* f_back;
const Bytecode* ip;
const CodeObject* co;
py_TValue module; // weak ref
py_GlobalRef module;
py_StackRef function; // a function object or NULL (global scope)
py_StackRef p0; // unwinding base
py_StackRef locals; // locals base
@ -46,7 +43,7 @@ typedef struct Frame {
} Frame;
Frame* Frame__new(const CodeObject* co,
py_TValue* module,
py_GlobalRef module,
py_StackRef function,
py_StackRef p0,
py_StackRef locals);
@ -66,7 +63,3 @@ int Frame__exit_block(Frame* self, ValueStack*, int);
void Frame__gc_mark(Frame* self);
UnwindTarget* Frame__find_unwind_target(Frame* self, int iblock);
void Frame__set_unwind_target(Frame* self, py_TValue* sp);
#ifdef __cplusplus
}
#endif

View File

@ -1,10 +1,6 @@
#include "pocketpy/objects/object.h"
#include "pocketpy/common/config.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ManagedHeap{
c11_vector no_gc;
c11_vector gen;
@ -28,7 +24,3 @@ PyObject* ManagedHeap__gcnew(ManagedHeap* self, py_Type type, int slots, int uds
// external implementation
void ManagedHeap__mark(ManagedHeap* self);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,10 @@
#pragma once
#include "pocketpy/interpreter/frame.h"
typedef struct Generator{
Frame* frame;
int state;
} Generator;
void pk_newgenerator(py_Ref out, Frame* frame, int slots);

View File

@ -1,14 +1,6 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void pk__add_module_pkpy();
void pk__add_module_os();
void pk__add_module_math();
void pk__add_module_dis();
#ifdef __cplusplus
}
#endif

View File

@ -6,10 +6,6 @@
#include "pocketpy/interpreter/frame.h"
#include "pocketpy/interpreter/modules.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct py_TypeInfo {
py_Name name;
py_Type base;
@ -69,6 +65,9 @@ bool pk__normalize_index(int* index, int length);
void pk_list__mark(void* ud, void (*marker)(py_TValue*));
void pk_dict__mark(void* ud, void (*marker)(py_TValue*));
bool pk_wrapper__self(int argc, py_Ref argv);
bool pk_wrapper__NotImplementedError(int argc, py_Ref argv);
typedef enum FrameResult {
RES_RETURN,
RES_CALL,
@ -126,9 +125,6 @@ py_Type pk_super__register();
py_Type pk_property__register();
py_Type pk_staticmethod__register();
py_Type pk_classmethod__register();
py_Type pk_generator__register();
py_TValue pk_builtins__register();
#ifdef __cplusplus
}
#endif

View File

@ -9,10 +9,6 @@
#include "pocketpy/common/utils.h"
#include "pocketpy/pocketpy.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct PyObject PyObject;
typedef struct VM VM;
extern VM* pk_current_vm;
@ -35,7 +31,3 @@ 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");
#ifdef __cplusplus
}
#endif

View File

@ -10,10 +10,6 @@
#include "pocketpy/objects/namedict.h"
#include "pocketpy/pocketpy.h"
#ifdef __cplusplus
extern "C" {
#endif
#define BC_NOARG 0
#define BC_KEEPLINE -1
@ -144,8 +140,4 @@ typedef struct Function {
} Function;
void Function__ctor(Function* self, FuncDecl_ decl, py_TValue* module);
void Function__dtor(Function* self);
#ifdef __cplusplus
}
#endif
void Function__dtor(Function* self);

View File

@ -7,10 +7,6 @@
#include "pocketpy/objects/object.h"
#include "pocketpy/pocketpy.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct{
SourceData_ src;
int lineno;
@ -20,7 +16,3 @@ typedef struct{
void py_BaseException__set_lineno(py_Ref, int lineno, const CodeObject* code);
int py_BaseException__get_lineno(py_Ref, const CodeObject* code);
void py_BaseException__stpush(py_Ref, SourceData_ src, int lineno, const char* func_name);
#ifdef __cplusplus
}
#endif

View File

@ -5,10 +5,6 @@
#include "pocketpy/objects/base.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define SMALLMAP_T__HEADER
#define K uint16_t
#define V py_TValue
@ -16,6 +12,3 @@ extern "C" {
#include "pocketpy/xmacros/smallmap.h"
#undef SMALLMAP_T__HEADER
#ifdef __cplusplus
}
#endif

View File

@ -3,10 +3,6 @@
#include "pocketpy/objects/namedict.h"
#include "pocketpy/objects/base.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct PyObject {
py_Type type; // we have a duplicated type here for convenience
bool gc_is_large;
@ -29,7 +25,3 @@ void* PyObject__userdata(PyObject* self);
PyObject* PyObject__new(py_Type type, int slots, int size);
void PyObject__delete(PyObject* self);
#ifdef __cplusplus
}
#endif

View File

@ -6,10 +6,6 @@
#include "pocketpy/common/sstream.h"
#include "pocketpy/common/vector.h"
#ifdef __cplusplus
extern "C" {
#endif
struct SourceData {
RefCounted rc;
enum py_CompileMode mode;
@ -38,7 +34,3 @@ void SourceData__snapshot(const struct SourceData* self,
int lineno,
const char* cursor,
const char* name);
#ifdef __cplusplus
}
#endif

View File

@ -385,7 +385,7 @@ void py_clearexc(py_StackRef p0);
#define ValueError(...) py_exception(tp_ValueError, __VA_ARGS__)
#define IndexError(...) py_exception(tp_IndexError, __VA_ARGS__)
#define ImportError(...) py_exception(tp_ImportError, __VA_ARGS__)
#define NotImplementedError() py_exception(tp_NotImplementedError, "")
#define ZeroDivisionError(...) py_exception(tp_ZeroDivisionError, __VA_ARGS__)
#define AttributeError(self, n) \
py_exception(tp_AttributeError, "'%t' object has no attribute '%n'", (self)->type, (n))
#define UnboundLocalError(n) \
@ -451,7 +451,6 @@ int py_list_len(py_Ref self);
void py_list_append(py_Ref self, py_Ref val);
void py_list_clear(py_Ref self);
void py_list_insert(py_Ref self, int i, py_Ref val);
void py_list_reverse(py_Ref self);
py_TmpRef py_dict_getitem(py_Ref self, py_Ref key) PY_RAISE;
void py_dict_setitem(py_Ref self, py_Ref key, py_Ref val) PY_RAISE;
@ -517,9 +516,10 @@ enum py_PredefinedTypes {
tp_NoneType,
tp_NotImplementedType,
tp_ellipsis,
tp_SyntaxError,
tp_StopIteration,
tp_generator,
/* builtin exceptions */
tp_StopIteration,
tp_SyntaxError,
tp_StackOverflowError,
tp_IOError,
tp_OSError,

View File

@ -27,21 +27,12 @@ with open("include/pocketpy/common/_generated.h", "wt", encoding='utf-8', newlin
data = '''#pragma once
// generated by prebuild.py
#ifdef __cplusplus
extern "C" {
#endif
const char* load_kPythonLib(const char* name);
'''
for key in sorted(sources.keys()):
value = sources[key]
data += f'extern const char kPythonLibs_{key}[];\n'
data += '''
#ifdef __cplusplus
} // extern "C"
#endif
'''
f.write(data)
with open("src/common/_generated.c", "wt", encoding='utf-8', newline='\n') as f:

View File

@ -1,80 +0,0 @@
class set:
def __init__(self, iterable=None):
iterable = iterable or []
self._a = {}
self.update(iterable)
def add(self, elem):
self._a[elem] = None
def discard(self, elem):
self._a.pop(elem, None)
def remove(self, elem):
del self._a[elem]
def clear(self):
self._a.clear()
def update(self, other):
for elem in other:
self.add(elem)
def __len__(self):
return len(self._a)
def copy(self):
return set(self._a.keys())
def __and__(self, other):
return {elem for elem in self if elem in other}
def __sub__(self, other):
return {elem for elem in self if elem not in other}
def __or__(self, other):
ret = self.copy()
ret.update(other)
return ret
def __xor__(self, other):
_0 = self - other
_1 = other - self
return _0 | _1
def union(self, other):
return self | other
def intersection(self, other):
return self & other
def difference(self, other):
return self - other
def symmetric_difference(self, other):
return self ^ other
def __eq__(self, other):
if not isinstance(other, set):
return NotImplemented
return len(self ^ other) == 0
def isdisjoint(self, other):
return len(self & other) == 0
def issubset(self, other):
return len(self - other) == 0
def issuperset(self, other):
return len(other - self) == 0
def __contains__(self, elem):
return elem in self._a
def __repr__(self):
if len(self) == 0:
return 'set()'
return '{'+ ', '.join([repr(i) for i in self._a.keys()]) + '}'
def __iter__(self):
return iter(self._a.keys())

View File

@ -1,4 +1,4 @@
from pkpy import next as __builtins_next
from pkpy import next as __pkpy_next
def all(iterable):
for i in iterable:
@ -37,8 +37,8 @@ def zip(a, b):
a = iter(a)
b = iter(b)
while True:
ai = __builtins_next(a)
bi = __builtins_next(b)
ai = __pkpy_next(a)
bi = __pkpy_next(b)
if ai is StopIteration or bi is StopIteration:
break
yield ai, bi
@ -182,36 +182,83 @@ def long(*args, **kwargs):
import _long
return _long.long(*args, **kwargs)
class set:
def __init__(self, iterable=None):
iterable = iterable or []
self._a = {}
self.update(iterable)
# builtin exceptions
class StackOverflowError(Exception): pass
class IOError(Exception): pass
class NotImplementedError(Exception): pass
class TypeError(Exception): pass
class IndexError(Exception): pass
class ValueError(Exception): pass
class RuntimeError(Exception): pass
class ZeroDivisionError(Exception): pass
class NameError(Exception): pass
class UnboundLocalError(Exception): pass
class AttributeError(Exception): pass
class ImportError(Exception): pass
class AssertionError(Exception): pass
def add(self, elem):
self._a[elem] = None
def discard(self, elem):
self._a.pop(elem, None)
class KeyError(Exception):
def __init__(self, key=...):
self.key = key
if key is ...:
super().__init__()
else:
super().__init__(repr(key))
def remove(self, elem):
del self._a[elem]
def clear(self):
self._a.clear()
def __str__(self):
if self.key is ...:
return ''
return str(self.key)
def update(self, other):
for elem in other:
self.add(elem)
def __len__(self):
return len(self._a)
def copy(self):
return set(self._a.keys())
def __and__(self, other):
return {elem for elem in self if elem in other}
def __sub__(self, other):
return {elem for elem in self if elem not in other}
def __or__(self, other):
ret = self.copy()
ret.update(other)
return ret
def __xor__(self, other):
_0 = self - other
_1 = other - self
return _0 | _1
def union(self, other):
return self | other
def intersection(self, other):
return self & other
def difference(self, other):
return self - other
def symmetric_difference(self, other):
return self ^ other
def __eq__(self, other):
if not isinstance(other, set):
return NotImplemented
return len(self ^ other) == 0
def isdisjoint(self, other):
return len(self & other) == 0
def issubset(self, other):
return len(self - other) == 0
def issuperset(self, other):
return len(other - self) == 0
def __contains__(self, elem):
return elem in self._a
def __repr__(self):
if self.key is ...:
return 'KeyError()'
return f'KeyError({self.key!r})'
if len(self) == 0:
return 'set()'
return '{'+ ', '.join([repr(i) for i in self._a.keys()]) + '}'
def __iter__(self):
return iter(self._a.keys())

View File

@ -1,171 +0,0 @@
"""Conversion functions between RGB and other color systems.
This modules provides two functions for each color system ABC:
rgb_to_abc(r, g, b) --> a, b, c
abc_to_rgb(a, b, c) --> r, g, b
All inputs and outputs are triples of floats in the range [0.0...1.0]
(with the exception of I and Q, which covers a slightly larger range).
Inputs outside the valid range may cause exceptions or invalid outputs.
Supported color systems:
RGB: Red, Green, Blue components
YIQ: Luminance, Chrominance (used by composite video signals)
HLS: Hue, Luminance, Saturation
HSV: Hue, Saturation, Value
"""
# References:
# http://en.wikipedia.org/wiki/YIQ
# http://en.wikipedia.org/wiki/HLS_color_space
# http://en.wikipedia.org/wiki/HSV_color_space
__all__ = ["rgb_to_yiq","yiq_to_rgb","rgb_to_hls","hls_to_rgb",
"rgb_to_hsv","hsv_to_rgb"]
# Some floating point constants
ONE_THIRD = 1.0/3.0
ONE_SIXTH = 1.0/6.0
TWO_THIRD = 2.0/3.0
# YIQ: used by composite video signals (linear combinations of RGB)
# Y: perceived grey level (0.0 == black, 1.0 == white)
# I, Q: color components
#
# There are a great many versions of the constants used in these formulae.
# The ones in this library uses constants from the FCC version of NTSC.
def rgb_to_yiq(r, g, b):
y = 0.30*r + 0.59*g + 0.11*b
i = 0.74*(r-y) - 0.27*(b-y)
q = 0.48*(r-y) + 0.41*(b-y)
return (y, i, q)
def yiq_to_rgb(y, i, q):
# r = y + (0.27*q + 0.41*i) / (0.74*0.41 + 0.27*0.48)
# b = y + (0.74*q - 0.48*i) / (0.74*0.41 + 0.27*0.48)
# g = y - (0.30*(r-y) + 0.11*(b-y)) / 0.59
r = y + 0.9468822170900693*i + 0.6235565819861433*q
g = y - 0.27478764629897834*i - 0.6356910791873801*q
b = y - 1.1085450346420322*i + 1.7090069284064666*q
if r < 0.0:
r = 0.0
if g < 0.0:
g = 0.0
if b < 0.0:
b = 0.0
if r > 1.0:
r = 1.0
if g > 1.0:
g = 1.0
if b > 1.0:
b = 1.0
return (r, g, b)
# HLS: Hue, Luminance, Saturation
# H: position in the spectrum
# L: color lightness
# S: color saturation
def rgb_to_hls(r, g, b):
maxc = max(r, g, b)
minc = min(r, g, b)
sumc = (maxc+minc)
rangec = (maxc-minc)
l = sumc/2.0
if minc == maxc:
return 0.0, l, 0.0
if l <= 0.5:
s = rangec / sumc
else:
s = rangec / (2.0-maxc-minc) # Not always 2.0-sumc: gh-106498.
rc = (maxc-r) / rangec
gc = (maxc-g) / rangec
bc = (maxc-b) / rangec
if r == maxc:
h = bc-gc
elif g == maxc:
h = 2.0+rc-bc
else:
h = 4.0+gc-rc
# h = (h/6.0) % 1.0
h = h / 6.0
h = h - int(h)
return h, l, s
def hls_to_rgb(h, l, s):
if s == 0.0:
return l, l, l
if l <= 0.5:
m2 = l * (1.0+s)
else:
m2 = l+s-(l*s)
m1 = 2.0*l - m2
return (_v(m1, m2, h+ONE_THIRD), _v(m1, m2, h), _v(m1, m2, h-ONE_THIRD))
def _v(m1, m2, hue):
# hue = hue % 1.0
hue = hue - int(hue)
if hue < ONE_SIXTH:
return m1 + (m2-m1)*hue*6.0
if hue < 0.5:
return m2
if hue < TWO_THIRD:
return m1 + (m2-m1)*(TWO_THIRD-hue)*6.0
return m1
# HSV: Hue, Saturation, Value
# H: position in the spectrum
# S: color saturation ("purity")
# V: color brightness
def rgb_to_hsv(r, g, b):
maxc = max(r, g, b)
minc = min(r, g, b)
rangec = (maxc-minc)
v = maxc
if minc == maxc:
return 0.0, 0.0, v
s = rangec / maxc
rc = (maxc-r) / rangec
gc = (maxc-g) / rangec
bc = (maxc-b) / rangec
if r == maxc:
h = bc-gc
elif g == maxc:
h = 2.0+rc-bc
else:
h = 4.0+gc-rc
# h = (h/6.0) % 1.0
h = h / 6.0
h = h - int(h)
return h, s, v
def hsv_to_rgb(h, s, v):
if s == 0.0:
return v, v, v
i = int(h*6.0) # XXX assume int() truncates!
f = (h*6.0) - i
p = v*(1.0 - s)
q = v*(1.0 - s*f)
t = v*(1.0 - s*(1.0-f))
i = i%6
if i == 0:
return v, t, p
if i == 1:
return q, v, p
if i == 2:
return p, v, t
if i == 3:
return p, q, v
if i == 4:
return t, p, v
if i == 5:
return v, p, q
# Cannot get here

View File

@ -1,17 +0,0 @@
cd c_bindings
rm -rf build
mkdir build
cd build
cmake ..
cmake --build . --config Release
./test_c_bindings > binding_test_scratch
echo "checking results (they should be identical)"
diff -q -s binding_test_scratch ../test_answers.txt
if [ $? -eq 1 ]
then
echo "ERROR: c binding test failed"
exit 1
fi

View File

@ -1,10 +1,10 @@
set -e
python prebuild.py
SRC_C=$(find src/ -name "*.c")
SRC_CPP=$(find src/ -name "*.cpp")
SRC="$SRC_C $SRC_CPP"
SRC=$(find src/ -name "*.c")
g++ -pg -Og -std=c++17 -frtti -Wfatal-errors -o main $SRC src2/main.cpp -Iinclude
gcc -pg -Og -std=c11 -Wfatal-errors -o main $SRC src2/main.c -Iinclude
./main benchmarks/fib.py
gprof main gmon.out > gprof.txt
rm gmon.out

View File

@ -1,10 +1,10 @@
set -e
python prebuild.py
SRC_C=$(find src/ -name "*.c")
SRC_CPP=$(find src/ -name "*.cpp")
SRC="$SRC_C $SRC_CPP"
SRC=$(find src/ -name "*.c")
clang++ -std=c++17 --coverage -O1 -stdlib=libc++ -frtti -Wfatal-errors -o main src2/main.cpp $SRC -Iinclude -DPK_ENABLE_OS=1 -DPK_DEBUG_PRECOMPILED_EXEC=1 -DPK_ENABLE_PROFILER=1
clang -std=c11 --coverage -O1 -Wfatal-errors -o main src2/main.c $SRC -Iinclude -DPK_ENABLE_OS=1 -DPK_DEBUG_PRECOMPILED_EXEC=1 -DPK_ENABLE_PROFILER=1
python scripts/run_tests.py

View File

@ -1,43 +0,0 @@
import re
filepath = 'include/pocketpy/vm.h'
with open(filepath, 'r', encoding='utf-8') as f:
lines = f.readlines()
REGION_PATTERN = re.compile(r'#if PK_REGION\("(.+)"\)')
current_region = None
output = []
def parse_line(line: str):
output.append(line)
for line in lines:
if current_region:
if line.startswith('#endif'):
current_region = None
output.append('```\n\n')
else:
parse_line(line.strip(' '))
else:
m = REGION_PATTERN.match(line)
if m:
current_region = m.group(1)
output.append(f'### {current_region}\n')
output.append('```cpp\n')
with open('docs/references.md', 'w', encoding='utf-8') as f:
f.write('''---
label: References
icon: code
order: 2
---
This page contains all useful methods of `VM` class.
''')
content = ''.join(output)
# replace {...} to ; (multi-line match)
content = re.sub(r'\{[^}]+?\}', r';', content, flags=re.DOTALL)
f.write(content)

View File

@ -10,7 +10,7 @@ def get_all_files(root: str):
continue
if file.startswith('_'):
continue
if not file.endswith('.cpp') and not file.endswith('.h') and not file.endswith('.hpp'):
if not file.endswith('.c') and not file.endswith('.h') and not file.endswith('.hpp'):
continue
yield fullpath

File diff suppressed because one or more lines are too long

View File

@ -232,6 +232,10 @@ int c11__byte_index_to_unicode(const char* data, int n) {
}
//////////////
bool c11_bytes__eq(c11_bytes* self, c11_bytes* other) {
if(self->size != other->size) return false;
return memcmp(self->data, other->data, self->size) == 0;
}
int c11_sv__cmp(c11_sv self, c11_sv other) {
int res = strncmp(self.data, other.data, c11__min(self.size, other.size));

View File

@ -134,7 +134,7 @@ FrameResult VM__run_top_frame(VM* self) {
case OP_LOAD_FUNCTION: {
FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg);
Function* ud = py_newobject(SP(), tp_function, 0, sizeof(Function));
Function__ctor(ud, decl, &frame->module);
Function__ctor(ud, decl, frame->module);
if(decl->nested) {
ud->closure = FastLocals__to_namedict(frame->locals, frame->co);
py_Name name = py_name(decl->code.name->data);
@ -173,7 +173,7 @@ FrameResult VM__run_top_frame(VM* self) {
PUSH(tmp);
DISPATCH();
}
tmp = py_getdict(&frame->module, name);
tmp = py_getdict(frame->module, name);
if(tmp != NULL) {
PUSH(tmp);
DISPATCH();
@ -193,7 +193,7 @@ FrameResult VM__run_top_frame(VM* self) {
PUSH(tmp);
DISPATCH();
}
tmp = py_getdict(&frame->module, name);
tmp = py_getdict(frame->module, name);
if(tmp != NULL) {
PUSH(tmp);
DISPATCH();
@ -208,7 +208,7 @@ FrameResult VM__run_top_frame(VM* self) {
}
case OP_LOAD_GLOBAL: {
py_Name name = byte.arg;
py_Ref tmp = py_getdict(&frame->module, name);
py_Ref tmp = py_getdict(frame->module, name);
if(tmp != NULL) {
PUSH(tmp);
DISPATCH();
@ -237,7 +237,7 @@ FrameResult VM__run_top_frame(VM* self) {
DISPATCH();
}
// load global if attribute not found
tmp = py_getdict(&frame->module, name);
tmp = py_getdict(frame->module, name);
if(tmp) {
PUSH(tmp);
DISPATCH();
@ -300,13 +300,13 @@ FrameResult VM__run_top_frame(VM* self) {
// }
}
} else {
py_setdict(&frame->module, name, TOP());
py_setdict(frame->module, name, TOP());
}
POP();
DISPATCH();
}
case OP_STORE_GLOBAL: {
py_setdict(&frame->module, byte.arg, TOP());
py_setdict(frame->module, byte.arg, TOP());
POP();
DISPATCH();
}
@ -361,7 +361,7 @@ FrameResult VM__run_top_frame(VM* self) {
// }
}
} else {
bool ok = py_deldict(&frame->module, name);
bool ok = py_deldict(frame->module, name);
if(!ok) {
NameError(name);
goto __ERROR;
@ -371,7 +371,7 @@ FrameResult VM__run_top_frame(VM* self) {
}
case OP_DELETE_GLOBAL: {
py_Name name = byte.arg;
bool ok = py_deldict(&frame->module, name);
bool ok = py_deldict(frame->module, name);
if(!ok) {
NameError(name);
goto __ERROR;
@ -701,7 +701,9 @@ FrameResult VM__run_top_frame(VM* self) {
DISPATCH();
}
case OP_YIELD_VALUE: {
assert(false);
py_assign(py_retval(), TOP());
POP();
return RES_YIELD;
}
/////////
case OP_LIST_APPEND: {
@ -800,7 +802,7 @@ FrameResult VM__run_top_frame(VM* self) {
ImportError("cannot import name '%n'", name);
goto __ERROR;
} else {
py_setdict(&frame->module, name, value);
py_setdict(frame->module, name, value);
}
}
} else {
@ -809,7 +811,7 @@ FrameResult VM__run_top_frame(VM* self) {
if(!kv->key) continue;
c11_sv name = py_name2sv(kv->key);
if(name.size == 0 || name.data[0] == '_') continue;
py_setdict(&frame->module, kv->key, &kv->value);
py_setdict(frame->module, kv->key, &kv->value);
}
}
POP();
@ -855,7 +857,7 @@ FrameResult VM__run_top_frame(VM* self) {
}
POP();
py_Type type =
pk_newtype(py_name2str(name), base, &frame->module, NULL, true, false);
pk_newtype(py_name2str(name), base, frame->module, NULL, true, false);
PUSH(py_tpobject(type));
self->__curr_class = TOP();
DISPATCH();
@ -864,7 +866,7 @@ FrameResult VM__run_top_frame(VM* self) {
// [cls or decorated]
py_Name name = byte.arg;
// set into f_globals
py_setdict(&frame->module, name, TOP());
py_setdict(frame->module, name, TOP());
if(py_istype(TOP(), tp_type)) {
// call on_end_subclass
@ -948,7 +950,7 @@ FrameResult VM__run_top_frame(VM* self) {
py_TValue* tmp = c11__at(py_TValue, &frame->co->consts, byte.arg);
const char* string = py_tostr(tmp);
// TODO: optimize this
if(!py_exec(string, "<eval>", EVAL_MODE, &frame->module)) goto __ERROR;
if(!py_exec(string, "<eval>", EVAL_MODE, frame->module)) goto __ERROR;
PUSH(py_retval());
DISPATCH();
}

View File

@ -1,6 +1,7 @@
#include "pocketpy/interpreter/frame.h"
#include "pocketpy/objects/codeobject.h"
#include "pocketpy/objects/object.h"
#include "pocketpy/pocketpy.h"
void ValueStack__ctor(ValueStack* self) {
self->sp = self->begin;
@ -35,7 +36,7 @@ UnwindTarget* UnwindTarget__new(UnwindTarget* next, int iblock, int offset) {
void UnwindTarget__delete(UnwindTarget* self) { free(self); }
Frame* Frame__new(const CodeObject* co,
py_TValue* module,
py_GlobalRef module,
py_StackRef function,
py_StackRef p0,
py_StackRef locals) {
@ -44,7 +45,7 @@ Frame* Frame__new(const CodeObject* co,
self->f_back = NULL;
self->ip = (Bytecode*)co->codes.data - 1;
self->co = co;
self->module = *module;
self->module = module;
self->function = function;
self->p0 = p0;
self->locals = locals;

View File

@ -0,0 +1,22 @@
#include "pocketpy/interpreter/generator.h"
#include "pocketpy/interpreter/frame.h"
#include "pocketpy/interpreter/vm.h"
#include "pocketpy/pocketpy.h"
void pk_newgenerator(py_Ref out, Frame* frame, int slots) {
Generator* ud = py_newobject(out, tp_generator, slots, sizeof(Generator));
ud->frame = frame;
ud->state = 0;
}
static bool generator__next__(int argc, py_Ref argv){
return true;
}
py_Type pk_generator__register() {
py_Type type = pk_newtype("generator", tp_object, NULL, NULL, false, true);
py_bindmagic(type, __iter__, pk_wrapper__self);
py_bindmagic(type, __next__, generator__next__);
return type;
}

View File

@ -2,6 +2,7 @@
#include "pocketpy/common/memorypool.h"
#include "pocketpy/common/sstream.h"
#include "pocketpy/common/utils.h"
#include "pocketpy/interpreter/generator.h"
#include "pocketpy/objects/base.h"
#include "pocketpy/common/_generated.h"
#include "pocketpy/pocketpy.h"
@ -126,9 +127,7 @@ void VM__ctor(VM* self) {
validate(tp_NotImplementedType,
pk_newtype("NotImplementedType", tp_object, NULL, NULL, false, true));
validate(tp_ellipsis, pk_newtype("ellipsis", tp_object, NULL, NULL, false, true));
validate(tp_SyntaxError, pk_newtype("SyntaxError", tp_Exception, NULL, NULL, false, true));
validate(tp_StopIteration, pk_newtype("StopIteration", tp_Exception, NULL, NULL, false, true));
validate(tp_generator, pk_generator__register());
self->builtins = pk_builtins__register();
@ -140,6 +139,8 @@ void VM__ctor(VM* self) {
validate(tp_##name, type); \
} while(0)
INJECT_BUILTIN_EXC(StopIteration);
INJECT_BUILTIN_EXC(SyntaxError);
INJECT_BUILTIN_EXC(StackOverflowError);
INJECT_BUILTIN_EXC(IOError);
INJECT_BUILTIN_EXC(OSError);
@ -160,11 +161,26 @@ void VM__ctor(VM* self) {
#undef validate
/* Setup Public Builtin Types */
py_Type public_types[] = {tp_object, tp_type, tp_int, tp_float,
tp_bool, tp_str, tp_list, tp_tuple,
tp_slice, tp_range, tp_bytes, tp_dict,
tp_property, tp_staticmethod, tp_classmethod, tp_super,
tp_BaseException, tp_Exception, tp_StopIteration, tp_SyntaxError};
py_Type public_types[] = {
tp_object,
tp_type,
tp_int,
tp_float,
tp_bool,
tp_str,
tp_list,
tp_tuple,
tp_slice,
tp_range,
tp_bytes,
tp_dict,
tp_property,
tp_staticmethod,
tp_classmethod,
tp_super,
tp_BaseException,
tp_Exception,
};
for(int i = 0; i < c11__count_array(public_types); i++) {
py_TypeInfo* ti = c11__at(py_TypeInfo, &self->types, public_types[i]);
@ -181,11 +197,13 @@ void VM__ctor(VM* self) {
// add python builtins
do {
bool ok = py_exec(kPythonLibs__set, "<builtins>", EXEC_MODE, &self->builtins);
if(!ok) {
py_printexc();
c11__abort("failed to load python builtins!");
}
bool ok;
ok = py_exec(kPythonLibs_builtins, "<builtins>", EXEC_MODE, &self->builtins);
if(!ok) goto __ABORT;
break;
__ABORT:
py_printexc();
c11__abort("failed to load python builtins!");
} while(0);
self->main = *py_newmodule("__main__");
@ -435,9 +453,14 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
// submit the call
VM__push_frame(self, Frame__new(co, &fn->module, p0, p0, argv));
return opcall ? RES_CALL : VM__run_top_frame(self);
case FuncType_GENERATOR:
assert(false);
break;
case FuncType_GENERATOR: {
bool ok = prepare_py_call(self->__vectorcall_buffer, argv, p1, kwargc, fn->decl);
if(!ok) return RES_ERROR;
Frame* frame = Frame__new(co, &fn->module, p0, p0, argv);
pk_newgenerator(py_retval(), frame, 0);
self->stack.sp = p0;
return RES_RETURN;
}
// prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl);
// s_data.reset(p0);
// callstack.emplace(nullptr, co, fn._module, callable.get(), nullptr);
@ -558,7 +581,7 @@ void ManagedHeap__mark(ManagedHeap* self) {
}
// mark frame
for(Frame* frame = vm->top_frame; frame; frame = frame->f_back) {
mark_value(&frame->module);
mark_value(frame->module);
}
// mark vm's registers
mark_value(&vm->last_retval);
@ -624,4 +647,14 @@ void pk_print_stack(VM* self, Frame* frame, Bytecode byte) {
byte.arg,
stack_str->data);
c11_string__delete(stack_str);
}
bool pk_wrapper__self(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
py_assign(py_retval(), argv);
return true;
}
bool pk_wrapper__NotImplementedError(int argc, py_Ref argv){
return py_exception(tp_NotImplementedError, "");
}

View File

@ -68,7 +68,7 @@ int py_import(const char* path_cstr) {
c11_sv top_filename = c11_string__sv(vm->top_frame->co->src->filename);
int is_init = c11_sv__endswith(top_filename, (c11_sv){"__init__.py", 11});
py_Ref package = py_getdict(&vm->top_frame->module, __path__);
py_Ref package = py_getdict(vm->top_frame->module, __path__);
c11_sv package_sv = py_tosv(package);
if(package_sv.size == 0) {
return ImportError("attempted relative import with no known parent package");
@ -170,14 +170,6 @@ static bool builtins_len(int argc, py_Ref argv) {
return py_len(argv);
}
static bool builtins_reversed(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
// convert _0 to list object
if(!py_tpcall(tp_list, 1, argv)) return false;
py_list_reverse(py_retval());
return true;
}
static bool builtins_hex(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
PY_CHECK_ARG_TYPE(0, tp_int);
@ -221,23 +213,6 @@ static bool builtins_next(int argc, py_Ref argv) {
return py_exception(tp_StopIteration, "");
}
static bool builtins_sorted(int argc, py_Ref argv) {
PY_CHECK_ARGC(3);
// convert _0 to list object
if(!py_tpcall(tp_list, 1, py_arg(0))) return false;
py_push(py_retval()); // duptop
py_push(py_retval()); // [| <list>]
bool ok = py_pushmethod(py_name("sort")); // [| list.sort, <list>]
if(!ok) return false;
py_push(py_arg(1)); // [| list.sort, <list>, key]
py_push(py_arg(2)); // [| list.sort, <list>, key, reverse]
ok = py_vectorcall(2, 0); // [| ]
if(!ok) return false;
py_assign(py_retval(), py_peek(-1));
py_pop();
return true;
}
static bool builtins_hash(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
py_i64 val;
@ -251,41 +226,9 @@ static bool builtins_abs(int argc, py_Ref argv) {
return pk_callmagic(__abs__, 1, argv);
}
static bool builtins_sum(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
if(!py_iter(py_arg(0))) return false;
py_push(py_retval()); // iter
py_i64 total_i64 = 0;
py_f64 total_f64 = 0.0;
bool is_float = false;
while(true) {
int res = py_next(py_peek(-1));
if(res == -1) {
py_pop();
return false;
}
if(res == 0) break;
py_Ref item = py_retval();
switch(item->type) {
case tp_int: total_i64 += item->_i64; break;
case tp_float:
is_float = true;
total_f64 += item->_f64;
break;
default: return TypeError("sum() expects an iterable of numbers");
}
}
if(is_float) {
py_newfloat(py_retval(), total_f64 + total_i64);
} else {
py_newint(py_retval(), total_i64);
}
py_pop();
return true;
static bool builtins_divmod(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
return pk_callmagic(__divmod__, 2, argv);
}
static bool builtins_print(int argc, py_Ref argv) {
@ -309,23 +252,18 @@ static bool builtins_print(int argc, py_Ref argv) {
return true;
}
static bool NoneType__repr__(int argc, py_Ref argv) {
py_newstr(py_retval(), "None");
return true;
}
static bool builtins_exec(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
PY_CHECK_ARG_TYPE(0, tp_str);
Frame* frame = pk_current_vm->top_frame;
return py_exec(py_tostr(argv), "<exec>", EXEC_MODE, &frame->module);
return py_exec(py_tostr(argv), "<exec>", EXEC_MODE, frame->module);
}
static bool builtins_eval(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
PY_CHECK_ARG_TYPE(0, tp_str);
Frame* frame = pk_current_vm->top_frame;
return py_exec(py_tostr(argv), "<eval>", EVAL_MODE, &frame->module);
return py_exec(py_tostr(argv), "<eval>", EVAL_MODE, frame->module);
}
static bool builtins_isinstance(int argc, py_Ref argv) {
@ -409,24 +347,57 @@ static bool builtins_delattr(int argc, py_Ref argv) {
return py_delattr(py_arg(0), name);
}
static bool builtins_chr(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
PY_CHECK_ARG_TYPE(0, tp_int);
py_i64 val = py_toint(py_arg(0));
if(val < 0 || val > 128) { return ValueError("chr() arg not in range(128)"); }
py_newstrn(py_retval(), (const char*)&val, 1);
return true;
}
static bool builtins_ord(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
PY_CHECK_ARG_TYPE(0, tp_str);
c11_sv sv = py_tosv(py_arg(0));
if(sv.size != 1) {
return TypeError("ord() expected a character, but string of length %d found", sv.size);
}
py_newint(py_retval(), sv.data[0]);
return true;
}
static bool NoneType__repr__(int argc, py_Ref argv) {
py_newstr(py_retval(), "None");
return true;
}
static bool ellipsis__repr__(int argc, py_Ref argv) {
py_newstr(py_retval(), "Ellipsis");
return true;
}
static bool NotImplementedType__repr__(int argc, py_Ref argv) {
py_newstr(py_retval(), "NotImplemented");
return true;
}
py_TValue pk_builtins__register() {
py_Ref builtins = py_newmodule("builtins");
py_bindfunc(builtins, "repr", builtins_repr);
py_bindfunc(builtins, "exit", builtins_exit);
py_bindfunc(builtins, "len", builtins_len);
py_bindfunc(builtins, "reversed", builtins_reversed);
py_bindfunc(builtins, "hex", builtins_hex);
py_bindfunc(builtins, "iter", builtins_iter);
py_bindfunc(builtins, "next", builtins_next);
py_bindfunc(builtins, "hash", builtins_hash);
py_bindfunc(builtins, "abs", builtins_abs);
py_bindfunc(builtins, "sum", builtins_sum);
py_bindfunc(builtins, "divmod", builtins_divmod);
py_bindfunc(builtins, "exec", builtins_exec);
py_bindfunc(builtins, "eval", builtins_eval);
py_bind(builtins, "print(*args, sep=' ', end='\\n')", builtins_print);
py_bind(builtins, "sorted(iterable, key=None, reverse=False)", builtins_sorted);
py_bindfunc(builtins, "isinstance", builtins_isinstance);
py_bindfunc(builtins, "issubclass", builtins_issubclass);
@ -436,8 +407,13 @@ py_TValue pk_builtins__register() {
py_bindfunc(builtins, "hasattr", builtins_hasattr);
py_bindfunc(builtins, "delattr", builtins_delattr);
// None __repr__
py_bindfunc(builtins, "chr", builtins_chr);
py_bindfunc(builtins, "ord", builtins_ord);
// some patches
py_bindmagic(tp_NoneType, __repr__, NoneType__repr__);
py_bindmagic(tp_ellipsis, __repr__, ellipsis__repr__);
py_bindmagic(tp_NotImplementedType, __repr__, NotImplementedType__repr__);
return *builtins;
}

View File

@ -457,12 +457,6 @@ py_Type pk_dict__register() {
}
//////////////////////////
static bool dict_items__iter__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
*py_retval() = *argv;
return true;
}
static bool dict_items__next__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
DictIterator* iter = py_touserdata(py_arg(0));
@ -478,7 +472,7 @@ static bool dict_items__next__(int argc, py_Ref argv) {
py_Type pk_dict_items__register() {
py_Type type = pk_newtype("dict_items", tp_object, NULL, NULL, false, true);
py_bindmagic(type, __iter__, dict_items__iter__);
py_bindmagic(type, __iter__, pk_wrapper__self);
py_bindmagic(type, __next__, dict_items__next__);
return type;
}

View File

@ -59,11 +59,6 @@ void py_list_insert(py_Ref self, int i, py_Ref val) {
c11_vector__insert(py_TValue, userdata, i, *val);
}
void py_list_reverse(py_Ref self) {
List* userdata = py_touserdata(self);
c11__reverse(py_TValue, userdata);
}
////////////////////////////////
static bool list__len__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);

View File

@ -36,10 +36,6 @@ py_Type pk_classmethod__register(){
}
/* boundmethod */
static bool boundmethod__new__(int argc, py_Ref argv) {
return NotImplementedError();
}
static bool boundmethod__self__getter(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
py_assign(py_retval(), py_getslot(argv, 0));
@ -55,7 +51,6 @@ static bool boundmethod__func__getter(int argc, py_Ref argv) {
py_Type pk_boundmethod__register(){
py_Type type = pk_newtype("boundmethod", tp_object, NULL, NULL, false, true);
py_bindmagic(type, __new__, boundmethod__new__);
py_bindproperty(type, "__self__", boundmethod__self__getter, NULL);
py_bindproperty(type, "__func__", boundmethod__func__getter, NULL);
return type;

View File

@ -83,8 +83,6 @@ static bool float__truediv__(int argc, py_Ref argv) {
return true;
}
#define ZeroDivisionError(msg) false
static bool number__pow__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
if(py_isint(&argv[0]) && py_isint(&argv[1])) {
@ -124,7 +122,7 @@ static bool int__floordiv__(int argc, py_Ref argv) {
py_i64 lhs = py_toint(&argv[0]);
if(py_isint(&argv[1])) {
py_i64 rhs = py_toint(&argv[1]);
if(rhs == 0) return -1;
if(rhs == 0) return ZeroDivisionError("integer division or modulo by zero");
py_newint(py_retval(), lhs / rhs);
} else {
py_newnotimplemented(py_retval());
@ -145,6 +143,19 @@ static bool int__mod__(int argc, py_Ref argv) {
return true;
}
static bool int__divmod__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
PY_CHECK_ARG_TYPE(1, tp_int);
py_i64 lhs = py_toint(&argv[0]);
py_i64 rhs = py_toint(&argv[1]);
if(rhs == 0) return ZeroDivisionError("integer division or modulo by zero");
py_newtuple(py_retval(), 2);
ldiv_t res = ldiv(lhs, rhs);
py_newint(py_getslot(py_retval(), 0), res.quot);
py_newint(py_getslot(py_retval(), 1), res.rem);
return true;
}
static bool int__invert__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
py_i64 val = py_toint(&argv[0]);
@ -459,9 +470,10 @@ void pk_number__register() {
py_bindmagic(tp_int, __pow__, number__pow__);
py_bindmagic(tp_float, __pow__, number__pow__);
// __floordiv__ & __mod__
// __floordiv__ & __mod__ & __divmod__
py_bindmagic(tp_int, __floordiv__, int__floordiv__);
py_bindmagic(tp_int, __mod__, int__mod__);
py_bindmagic(tp_int, __divmod__, int__divmod__);
// int.__invert__ & int.<BITWISE OP>
py_bindmagic(tp_int, __invert__, int__invert__);

View File

@ -68,12 +68,6 @@ static bool range_iterator__new__(int argc, py_Ref argv) {
return true;
}
static bool range_iterator__iter__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
*py_retval() = *py_arg(0);
return true;
}
static bool range_iterator__next__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
RangeIterator* ud = py_touserdata(py_arg(0));
@ -91,7 +85,7 @@ py_Type pk_range_iterator__register() {
py_Type type = pk_newtype("range_iterator", tp_object, NULL, NULL, false, true);
py_bindmagic(type, __new__, range_iterator__new__);
py_bindmagic(type, __iter__, range_iterator__iter__);
py_bindmagic(type, __iter__, pk_wrapper__self);
py_bindmagic(type, __next__, range_iterator__next__);
return type;
}

View File

@ -190,7 +190,7 @@ static bool str__getitem__(int argc, py_Ref argv) {
}
#define DEF_STR_CMP_OP(op, __f, __cond) \
static bool str##op(int argc, py_Ref argv) { \
static bool str##op(int argc, py_Ref argv) { \
PY_CHECK_ARGC(2); \
c11_string* self = py_touserdata(&argv[0]); \
if(py_arg(1)->type != tp_str) { \
@ -355,17 +355,11 @@ static bool str__strip_impl(bool left, bool right, int argc, py_Ref argv) {
return true;
}
static bool str_strip(int argc, py_Ref argv) {
return str__strip_impl(true, true, argc, argv);
}
static bool str_strip(int argc, py_Ref argv) { return str__strip_impl(true, true, argc, argv); }
static bool str_lstrip(int argc, py_Ref argv) {
return str__strip_impl(true, false, argc, argv);
}
static bool str_lstrip(int argc, py_Ref argv) { return str__strip_impl(true, false, argc, argv); }
static bool str_rstrip(int argc, py_Ref argv) {
return str__strip_impl(false, true, argc, argv);
}
static bool str_rstrip(int argc, py_Ref argv) { return str__strip_impl(false, true, argc, argv); }
static bool str_zfill(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
@ -423,13 +417,9 @@ static bool str__widthjust_impl(bool left, int argc, py_Ref argv) {
return true;
}
static bool str_ljust(int argc, py_Ref argv) {
return str__widthjust_impl(true, argc, argv);
}
static bool str_ljust(int argc, py_Ref argv) { return str__widthjust_impl(true, argc, argv); }
static bool str_rjust(int argc, py_Ref argv) {
return str__widthjust_impl(false, argc, argv);
}
static bool str_rjust(int argc, py_Ref argv) { return str__widthjust_impl(false, argc, argv); }
static bool str_find(int argc, py_Ref argv) {
if(argc > 3) return TypeError("find() takes at most 3 arguments");
@ -453,6 +443,15 @@ static bool str_index(int argc, py_Ref argv) {
return true;
}
static bool str_encode(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
int size;
const char* data = py_tostrn(argv, &size);
unsigned char* p = py_newbytes(py_retval(), size);
memcpy(p, data, size);
return true;
}
py_Type pk_str__register() {
py_Type type = pk_newtype("str", tp_object, NULL, NULL, false, true);
// no need to dtor because the memory is controlled by the object
@ -492,15 +491,10 @@ py_Type pk_str__register() {
py_bindmethod(tp_str, "rjust", str_rjust);
py_bindmethod(tp_str, "find", str_find);
py_bindmethod(tp_str, "index", str_index);
py_bindmethod(tp_str, "encode", str_encode);
return type;
}
static bool str_iterator__iter__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
*py_retval() = argv[0];
return true;
}
static bool str_iterator__next__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
int* ud = py_touserdata(&argv[0]);
@ -517,14 +511,127 @@ static bool str_iterator__next__(int argc, py_Ref argv) {
py_Type pk_str_iterator__register() {
py_Type type = pk_newtype("str_iterator", tp_object, NULL, NULL, false, true);
py_bindmagic(type, __iter__, str_iterator__iter__);
py_bindmagic(type, __iter__, pk_wrapper__self);
py_bindmagic(type, __next__, str_iterator__next__);
return type;
}
static bool bytes__new__(int argc, py_Ref argv){
if(argc == 1){
py_newbytes(py_retval(), 0);
return true;
}
if(argc > 2) return TypeError("bytes() takes at most 1 argument");
int length;
py_TValue* p = pk_arrayview(&argv[1], &length);
if(!p) return TypeError("bytes() argument must be a list or tuple");
unsigned char* data = py_newbytes(py_retval(), length);
for(int i = 0; i < length; i++){
if(!py_checktype(&p[i], tp_int)) return false;
py_i64 v = py_toint(&p[i]);
if(v < 0 || v > 255) return ValueError("bytes must be in range(0, 256)");
data[i] = v;
}
return true;
}
static bool bytes__repr__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
c11_bytes* self = py_touserdata(&argv[0]);
c11_sbuf buf;
c11_sbuf__ctor(&buf);
c11_sbuf__write_char(&buf, 'b');
c11_sbuf__write_quoted(&buf, (c11_sv){(const char*)self->data, self->size}, '\'');
c11_sbuf__py_submit(&buf, py_retval());
return true;
}
static bool bytes__getitem__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
int size;
unsigned char* data = py_tobytes(&argv[0], &size);
py_Ref _1 = py_arg(1);
if(_1->type == tp_int) {
int index = py_toint(_1);
if(!pk__normalize_index(&index, size)) return false;
py_newint(py_retval(), data[index]);
return true;
} else if(_1->type == tp_slice) {
int start, stop, step;
bool ok = pk__parse_int_slice(_1, size, &start, &stop, &step);
if(!ok) return false;
c11_vector res;
c11_vector__ctor(&res, sizeof(unsigned char));
for(int i = start; step > 0 ? i < stop : i > stop; i += step) {
c11_vector__push(unsigned char, &res, data[i]);
}
unsigned char* p = py_newbytes(py_retval(), res.count);
memcpy(p, res.data, res.count);
c11_vector__dtor(&res);
return true;
} else {
return TypeError("bytes indices must be integers");
}
}
static bool bytes__eq__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
c11_bytes* self = py_touserdata(&argv[0]);
if(!py_istype(&argv[1], tp_bytes)) {
py_newnotimplemented(py_retval());
} else {
c11_bytes* other = py_touserdata(&argv[1]);
py_newbool(py_retval(), c11_bytes__eq(self, other));
}
return true;
}
static bool bytes__ne__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
c11_bytes* self = py_touserdata(&argv[0]);
if(!py_istype(&argv[1], tp_bytes)) {
py_newnotimplemented(py_retval());
} else {
c11_bytes* other = py_touserdata(&argv[1]);
py_newbool(py_retval(), !c11_bytes__eq(self, other));
}
return true;
}
static bool bytes__add__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
c11_bytes* self = py_touserdata(&argv[0]);
if(py_arg(1)->type != tp_bytes) {
py_newnotimplemented(py_retval());
} else {
c11_bytes* other = py_touserdata(&argv[1]);
unsigned char* p = py_newbytes(py_retval(), self->size + other->size);
memcpy(p, self->data, self->size);
memcpy(p + self->size, other->data, other->size);
}
return true;
}
static bool bytes_decode(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
int size;
unsigned char* data = py_tobytes(&argv[0], &size);
py_newstrn(py_retval(), (const char*)data, size);
return true;
}
py_Type pk_bytes__register() {
py_Type type = pk_newtype("bytes", tp_object, NULL, NULL, false, true);
// no need to dtor because the memory is controlled by the object
py_bindmagic(tp_bytes, __new__, bytes__new__);
py_bindmagic(tp_bytes, __repr__, bytes__repr__);
py_bindmagic(tp_bytes, __getitem__, bytes__getitem__);
py_bindmagic(tp_bytes, __eq__, bytes__eq__);
py_bindmagic(tp_bytes, __ne__, bytes__ne__);
py_bindmagic(tp_bytes, __add__, bytes__add__);
py_bindmethod(tp_bytes, "decode", bytes_decode);
return type;
}

View File

@ -13,7 +13,8 @@ assert b'\xff\xee' == b'\xff\xee'
a = '测试123'
assert a == a.encode().decode()
assert chr(0) == '\x00'
assert ord('\x00') == 0
# test slice
s = b"football"
@ -33,4 +34,8 @@ assert a[::-1] == b"!dlroW ,olleH"
assert a[::2] == b"Hlo ol!"
assert a[2:5:2] == b"lo"
assert a[5:2:-1] == b",ol"
assert a[5:2:-2] == b",l"
assert a[5:2:-2] == b",l"
assert bytes() == b''
assert bytes((65,)) == b'A'
assert bytes([0, 1, 2, 3]) == b'\x00\x01\x02\x03'

View File

@ -1,21 +0,0 @@
a = '测试 123'
a = a.encode()
import base64
b = base64.b64encode(a)
c = base64.b64decode(b)
assert a == c
data = [66, 110, 145, 18, 176, 13, 255, 202, 173, 109, 178, 194, 171, 198, 143, 24, 113, 46, 70, 94, 71, 140, 159, 191, 134, 230, 190, 224, 223, 94, 217, 20, 241, 138, 104, 120, 249, 91, 134, 48, 108, 49, 0, 249, 235, 225, 228, 190, 63, 204, 216, 102, 153, 51, 79, 221, 234, 252, 231, 156, 74, 23, 131, 161, 172, 157, 26, 15, 88, 28, 21, 170, 86, 177, 177, 249, 111, 230, 35, 180, 61, 140, 33, 14, 74, 238, 253, 19, 177, 76, 249, 21, 35, 105, 24, 136, 187, 121, 71, 202, 239, 235, 71, 126, 60, 37, 83, 186, 102, 114, 95, 212, 81, 48, 102, 167, 208, 66, 250, 132, 199, 137, 141, 231, 126, 219, 125, 1, 86, 87, 132, 161, 55, 166, 192, 27, 95, 27, 237, 225, 32, 240, 234, 160, 247, 143, 241, 232, 195, 117, 83, 133, 69, 178, 239, 123, 144, 172, 34, 43, 56, 136, 184, 68, 65, 70, 61, 164, 109, 134, 142, 153, 125, 154, 62, 117, 166, 86, 234, 39, 73, 207, 67, 91, 88, 220, 43, 148, 201, 185, 128, 93, 151, 210, 167, 82, 87, 246, 171, 125, 210, 46, 60, 156, 4, 173, 219, 149, 24, 226, 63, 176, 92, 103, 126, 201, 254, 6, 186, 233, 165, 169, 237, 141, 252, 0, 195, 212, 222, 186, 103, 15, 137, 41, 251, 16, 163, 22, 177, 232, 205, 58, 50, 205, 89, 249, 38, 45, 98, 42, 155, 33, 225, 232, 16, 157, 91, 246, 207, 164, 150, 214, 76, 151, 179, 203, 67, 194, 213, 83, 2, 106, 109, 254, 15, 110, 168, 19, 114, 185, 174, 20, 106, 141, 116, 222, 205, 135, 222, 110, 90, 27, 61, 6, 118, 50, 155, 6, 224, 213, 109, 98, 252, 84, 166, 77, 124, 187, 187, 113, 173, 45, 17, 232, 208, 126, 248, 239, 18, 33, 205, 117, 44, 32, 223, 1, 221, 210, 41, 67, 28, 218, 218, 161, 209, 11, 93, 250, 96, 2, 43, 157, 217, 134, 183, 24, 105, 177, 74, 214, 18, 114, 191, 64, 195, 94, 194, 19, 115, 211, 103, 49, 218, 87, 8, 199, 50, 225, 174, 222, 75, 23, 159, 76, 56, 208, 224, 172, 48, 197, 126, 159, 191, 80, 216, 148, 30, 114, 231, 142, 100, 159, 67, 77, 190, 64, 182, 21, 108, 4, 232, 73, 145, 247, 196, 220, 197, 234, 55, 241, 212, 115, 115, 142, 172, 248, 132, 117, 115, 107, 176, 230, 130, 189, 160, 150, 63, 79, 253, 240, 113, 61, 222, 46, 102, 118, 100, 208, 170, 0, 60, 154, 102, 168, 241, 159, 146, 71, 55, 244, 123, 82, 49, 64, 231, 190, 49, 51, 16, 111, 153, 209, 208, 116, 19, 68, 139, 208, 105, 248, 80, 12, 237, 29, 63, 80, 127, 1, 118, 22, 39, 83, 25, 220, 75, 31, 152, 16, 94, 254, 141, 55, 6, 89, 45, 247, 229, 209, 239, 223, 226, 124, 50, 51, 219, 110, 100, 251, 122, 53, 166, 63, 43, 116, 190, 114, 169, 72, 18, 190, 55, 4, 249, 3, 200, 99, 0, 37, 94, 50, 58, 37, 56, 154, 18, 154, 127, 123, 187, 123, 110, 131, 14, 185, 76, 193, 11, 227, 36, 184, 88, 3, 222, 126, 32, 143, 125, 180, 104, 142, 84, 22, 53, 2, 38, 188, 187, 51, 163, 189, 25, 215, 94, 190, 196, 213, 155, 23, 84, 206, 237, 125, 76, 185, 12, 111, 201, 249, 101, 50, 217, 32, 3, 37, 49, 177, 4, 10, 123, 29, 126, 106, 108, 246, 89, 42, 182, 135, 11, 152, 122, 12, 23, 159, 212, 53, 44, 244, 48, 251, 130, 109, 191, 76, 148, 226, 83, 55, 225, 100, 196, 166, 171, 108, 91, 67, 226, 207, 143, 73, 81, 95, 69, 92, 141, 150, 108, 168, 235, 1, 33, 160, 158, 62, 149, 0, 200, 228, 176, 38, 112, 18, 253, 239, 107, 214, 17, 22, 112, 255, 117, 155, 248, 59, 113, 100, 145, 101, 245, 113, 230, 167, 58, 232, 195, 51, 76, 26, 7, 94, 201, 198, 96, 93, 8, 231, 60, 139, 37, 191, 37, 101, 155, 83, 246, 181, 109, 149, 241, 96, 168, 126, 232, 54, 230, 197, 179, 214, 148, 79, 13, 27, 195, 164, 146, 183, 129, 82, 82, 177, 2, 255, 8, 85, 214, 83, 244, 237, 143, 104, 107, 28, 215, 178, 46, 71, 175, 186, 77, 191, 93, 13, 204, 154, 234, 193, 231, 49, 27, 7, 66, 53, 170, 63, 3, 172, 177, 176, 255, 249, 116, 172, 165, 78, 64, 218, 147, 214, 206, 68, 42, 186, 119, 75, 28, 141, 187, 117, 21, 89, 69, 96, 79, 211, 1, 141]
data = bytes(data)
encoded = base64.b64encode(data)
res = 'Qm6RErAN/8qtbbLCq8aPGHEuRl5HjJ+/hua+4N9e2RTximh4+VuGMGwxAPnr4eS+P8zYZpkzT93q/OecSheDoaydGg9YHBWqVrGx+W/mI7Q9jCEOSu79E7FM+RUjaRiIu3lHyu/rR348JVO6ZnJf1FEwZqfQQvqEx4mN537bfQFWV4ShN6bAG18b7eEg8Oqg94/x6MN1U4VFsu97kKwiKziIuERBRj2kbYaOmX2aPnWmVuonSc9DW1jcK5TJuYBdl9KnUlf2q33SLjycBK3blRjiP7BcZ37J/ga66aWp7Y38AMPU3rpnD4kp+xCjFrHozToyzVn5Ji1iKpsh4egQnVv2z6SW1kyXs8tDwtVTAmpt/g9uqBNyua4Uao103s2H3m5aGz0GdjKbBuDVbWL8VKZNfLu7ca0tEejQfvjvEiHNdSwg3wHd0ilDHNraodELXfpgAiud2Ya3GGmxStYScr9Aw17CE3PTZzHaVwjHMuGu3ksXn0w40OCsMMV+n79Q2JQecueOZJ9DTb5AthVsBOhJkffE3MXqN/HUc3OOrPiEdXNrsOaCvaCWP0/98HE93i5mdmTQqgA8mmao8Z+SRzf0e1IxQOe+MTMQb5nR0HQTRIvQafhQDO0dP1B/AXYWJ1MZ3EsfmBBe/o03Blkt9+XR79/ifDIz225k+3o1pj8rdL5yqUgSvjcE+QPIYwAlXjI6JTiaEpp/e7t7boMOuUzBC+MkuFgD3n4gj320aI5UFjUCJry7M6O9GddevsTVmxdUzu19TLkMb8n5ZTLZIAMlMbEECnsdfmps9lkqtocLmHoMF5/UNSz0MPuCbb9MlOJTN+FkxKarbFtD4s+PSVFfRVyNlmyo6wEhoJ4+lQDI5LAmcBL972vWERZw/3Wb+DtxZJFl9XHmpzrowzNMGgdeycZgXQjnPIslvyVlm1P2tW2V8WCofug25sWz1pRPDRvDpJK3gVJSsQL/CFXWU/Ttj2hrHNeyLkevuk2/XQ3MmurB5zEbB0I1qj8DrLGw//l0rKVOQNqT1s5EKrp3SxyNu3UVWUVgT9MBjQ=='
assert encoded.decode() == res
decoded = base64.b64decode(encoded)
assert decoded == data

View File

@ -1,50 +0,0 @@
import csv
def test(data: str, expected):
ret = list(csv.reader(data.splitlines()))
assert ret==expected, f"Expected {expected}, got {ret}"
test("""a,b,c
1,2,3
""", [['a', 'b', 'c'], ['1', '2', '3']])
test("""a,b,c
1,2,"3"
""", [['a', 'b', 'c'], ['1', '2', '3']])
test("""a,b,c
1,2,"3,,"
""", [['a', 'b', 'c'], ['1', '2', '3,,']])
test("""a,b,c
1,2,'3'
""", [['a', 'b', 'c'], ['1', '2', '\'3\'']])
test('''a,b,c
1,2,"123"""
''', [['a', 'b', 'c'], ['1', '2', '123"']])
test("""a,b,c,
1,2,3,
""", [['a', 'b', 'c', ''], ['1', '2', '3', '']])
test("""a,b ,c,
1,"22""33",3
""", [['a', 'b ', 'c', ''], ['1', '22"33', '3']])
# newline
test('''a,b,c
1,2,"3,
4"
5,"a,""
b",7
''', [['a', 'b', 'c'], ['1', '2', '3,\n 4'], ['5', 'a,"\nb', '7']])
ret = csv.DictReader("""a,b,c
1,2,3
"4",5,6
""".splitlines())
assert list(ret)==[
{'a': '1', 'b': '2', 'c': '3'},
{'a': '4', 'b': '5', 'c': '6'},
]