Compare commits

...

6 Commits

Author SHA1 Message Date
blueloveTH
0e7936341b ... 2024-08-11 01:14:36 +08:00
blueloveTH
2930da4e7f ... 2024-08-10 22:02:21 +08:00
blueloveTH
1b5b9fa6cb ... 2024-08-10 21:48:28 +08:00
blueloveTH
c4c7b9ef25 ... 2024-08-10 21:38:40 +08:00
blueloveTH
0f5ce54c66 ... 2024-08-10 20:29:44 +08:00
blueloveTH
88f893ddd7 ... 2024-08-10 20:21:40 +08:00
58 changed files with 579 additions and 767 deletions

View File

@ -89,3 +89,7 @@ if(PK_USE_CJSON)
target_link_libraries(${PROJECT_NAME} PRIVATE cjson) target_link_libraries(${PROJECT_NAME} PRIVATE cjson)
endif() endif()
# link math library
if(UNIX)
target_link_libraries(${PROJECT_NAME} PRIVATE m)
endif()

View File

@ -22,7 +22,7 @@ SRC=$(find src/ -name "*.c")
echo "> Compiling and linking source files... " echo "> Compiling and linking source files... "
FLAGS="-std=c11 -O1 -Wfatal-errors -Iinclude" FLAGS="-std=c11 -O1 -Wfatal-errors -Iinclude -DNDEBUG"
if [[ "$OSTYPE" == "darwin"* ]]; then if [[ "$OSTYPE" == "darwin"* ]]; then
LIB_EXTENSION=".dylib" LIB_EXTENSION=".dylib"
@ -33,7 +33,7 @@ else
LINK_FLAGS="-Wl,-rpath=." LINK_FLAGS="-Wl,-rpath=."
fi fi
clang $FLAGS -o libpocketpy$LIB_EXTENSION $SRC -fPIC -shared clang $FLAGS -o libpocketpy$LIB_EXTENSION $SRC -fPIC -shared -lm
# compile main.cpp and link to libpocketpy.so # compile main.cpp and link to libpocketpy.so
echo "> Compiling main.c and linking to libpocketpy$LIB_EXTENSION..." echo "> Compiling main.c and linking to libpocketpy$LIB_EXTENSION..."

View File

@ -18,17 +18,17 @@ assert config in ['Debug', 'Release', 'RelWithDebInfo']
os.chdir("build") os.chdir("build")
code = os.system(f"cmake .. -DPK_USE_CJSON=ON -DPK_ENABLE_OS=ON -DCMAKE_BUILD_TYPE={config}") code = os.system(f"cmake .. -DPK_ENABLE_OS=ON -DCMAKE_BUILD_TYPE={config}")
assert code == 0 assert code == 0
code = os.system(f"cmake --build . --config {config}") code = os.system(f"cmake --build . --config {config}")
assert code == 0 assert code == 0
if sys.platform == "win32": if sys.platform == "win32":
shutil.copy(f"{config}/main.exe", "../main.exe") shutil.copy(f"{config}/main.exe", "../main.exe")
shutil.copy(f"{config}/pocketpy.dll", "../pocketpy.dll") # shutil.copy(f"{config}/pocketpy.dll", "../pocketpy.dll")
elif sys.platform == "darwin": elif sys.platform == "darwin":
shutil.copy("main", "../main") shutil.copy("main", "../main")
shutil.copy("libpocketpy.dylib", "../libpocketpy.dylib") # shutil.copy("libpocketpy.dylib", "../libpocketpy.dylib")
else: else:
shutil.copy("main", "../main") shutil.copy("main", "../main")
shutil.copy("libpocketpy.so", "../libpocketpy.so") # shutil.copy("libpocketpy.so", "../libpocketpy.so")

View File

@ -4,7 +4,6 @@
const char* load_kPythonLib(const char* name); const char* load_kPythonLib(const char* name);
extern const char kPythonLibs__enum[]; extern const char kPythonLibs__enum[];
extern const char kPythonLibs__long[];
extern const char kPythonLibs_bisect[]; extern const char kPythonLibs_bisect[];
extern const char kPythonLibs_builtins[]; extern const char kPythonLibs_builtins[];
extern const char kPythonLibs_cmath[]; extern const char kPythonLibs_cmath[];

View File

@ -10,7 +10,7 @@ extern const char* TokenSymbols[];
typedef enum TokenIndex{ typedef enum TokenIndex{
TK_EOF, TK_EOL, TK_SOF, TK_EOF, TK_EOL, TK_SOF,
TK_ID, TK_NUM, TK_STR, TK_FSTR, TK_LONG, TK_BYTES, TK_IMAG, TK_ID, TK_NUM, TK_STR, TK_FSTR, TK_BYTES, TK_IMAG,
TK_INDENT, TK_DEDENT, TK_INDENT, TK_DEDENT,
/***************/ /***************/
TK_IS_NOT, TK_NOT_IN, TK_YIELD_FROM, TK_IS_NOT, TK_NOT_IN, TK_YIELD_FROM,

View File

@ -2,6 +2,7 @@
void pk__add_module_pkpy(); void pk__add_module_pkpy();
void pk__add_module_os(); void pk__add_module_os();
void pk__add_module_sys();
void pk__add_module_math(); void pk__add_module_math();
void pk__add_module_dis(); void pk__add_module_dis();
void pk__add_module_random(); void pk__add_module_random();

View File

@ -6,6 +6,11 @@
#include "pocketpy/interpreter/frame.h" #include "pocketpy/interpreter/frame.h"
#include "pocketpy/interpreter/modules.h" #include "pocketpy/interpreter/modules.h"
// TODO:
// 1. __eq__ and __ne__ fallbacks
// 2. un-cleared exception detection
// 3. super()
typedef struct py_TypeInfo { typedef struct py_TypeInfo {
py_Name name; py_Name name;
py_Type base; py_Type base;
@ -89,8 +94,8 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
const char* pk_opname(Opcode op); const char* pk_opname(Opcode op);
py_TValue* pk_arrayview(py_Ref self, int* length); int pk_arrayview(py_Ref self, py_TValue** p);
int pk_arrayequal(py_TValue* lhs, int lhs_length, py_TValue* rhs, int rhs_length); bool pk_wrapper__arrayequal(py_Type type, int argc, py_Ref argv);
bool pk_arrayiter(py_Ref val); bool pk_arrayiter(py_Ref val);
bool pk_arraycontains(py_Ref self, py_Ref val); bool pk_arraycontains(py_Ref self, py_Ref val);

View File

@ -460,7 +460,7 @@ bool py_call(py_Ref f, int argc, py_Ref argv) PY_RAISE;
/// This function does extra checks to help you debug `py_CFunction`. /// 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;
#else #else
#define py_callcfunc(f, argc, argv) f(argc, argv) #define py_callcfunc(f, argc, argv) (f((argc), (argv)))
#endif #endif
/// Python equivalent to `str(val)`. /// Python equivalent to `str(val)`.

View File

@ -42,7 +42,6 @@ OPCODE(DELETE_GLOBAL)
OPCODE(DELETE_ATTR) OPCODE(DELETE_ATTR)
OPCODE(DELETE_SUBSCR) OPCODE(DELETE_SUBSCR)
/**************************/ /**************************/
OPCODE(BUILD_LONG)
OPCODE(BUILD_IMAG) OPCODE(BUILD_IMAG)
OPCODE(BUILD_BYTES) OPCODE(BUILD_BYTES)
OPCODE(BUILD_TUPLE) OPCODE(BUILD_TUPLE)

View File

@ -1,352 +0,0 @@
# after v1.2.2, int is always 64-bit
PyLong_SHIFT = 60//2 - 1
PyLong_BASE = 2 ** PyLong_SHIFT
PyLong_MASK = PyLong_BASE - 1
PyLong_DECIMAL_SHIFT = 4
PyLong_DECIMAL_BASE = 10 ** PyLong_DECIMAL_SHIFT
##############################################################
def ulong_fromint(x: int):
# return a list of digits and sign
if x == 0: return [0], 1
sign = 1 if x > 0 else -1
if sign < 0: x = -x
res = []
while x:
res.append(x & PyLong_MASK)
x >>= PyLong_SHIFT
return res, sign
def ulong_cmp(a: list, b: list) -> int:
# return 1 if a>b, -1 if a<b, 0 if a==b
if len(a) > len(b): return 1
if len(a) < len(b): return -1
for i in range(len(a)-1, -1, -1):
if a[i] > b[i]: return 1
if a[i] < b[i]: return -1
return 0
def ulong_pad_(a: list, size: int):
# pad leading zeros to have `size` digits
delta = size - len(a)
if delta > 0:
a.extend([0] * delta)
def ulong_unpad_(a: list):
# remove leading zeros
while len(a)>1 and a[-1]==0:
a.pop()
def ulong_add(a: list, b: list) -> list:
res = [0] * max(len(a), len(b))
ulong_pad_(a, len(res))
ulong_pad_(b, len(res))
carry = 0
for i in range(len(res)):
carry += a[i] + b[i]
res[i] = carry & PyLong_MASK
carry >>= PyLong_SHIFT
if carry > 0:
res.append(carry)
return res
def ulong_inc_(a: list):
a[0] += 1
for i in range(len(a)):
if a[i] < PyLong_BASE: break
a[i] -= PyLong_BASE
if i+1 == len(a):
a.append(1)
else:
a[i+1] += 1
def ulong_sub(a: list, b: list) -> list:
# a >= b
res = []
borrow = 0
for i in range(len(b)):
tmp = a[i] - b[i] - borrow
if tmp < 0:
tmp += PyLong_BASE
borrow = 1
else:
borrow = 0
res.append(tmp)
for i in range(len(b), len(a)):
tmp = a[i] - borrow
if tmp < 0:
tmp += PyLong_BASE
borrow = 1
else:
borrow = 0
res.append(tmp)
ulong_unpad_(res)
return res
def ulong_divmodi(a: list, b: int):
# b > 0
res = []
carry = 0
for i in range(len(a)-1, -1, -1):
carry <<= PyLong_SHIFT
carry += a[i]
res.append(carry // b)
carry %= b
res.reverse()
ulong_unpad_(res)
return res, carry
def ulong_divmod(a: list, b: list):
if ulong_cmp(a, b) < 0:
return [0], a
if len(b) == 1:
q, r = ulong_divmodi(a, b[0])
r, _ = ulong_fromint(r)
return q, r
max = (len(a) - len(b)) * PyLong_SHIFT + \
(a[-1].bit_length() - b[-1].bit_length())
low = [0]
high = (max // PyLong_SHIFT) * [0] + \
[(2**(max % PyLong_SHIFT)) & PyLong_MASK]
while ulong_cmp(low, high) < 0:
ulong_inc_(high)
mid, r = ulong_divmodi(ulong_add(low, high), 2)
if ulong_cmp(a, ulong_mul(b, mid)) >= 0:
low = mid
else:
high = ulong_sub(mid, [1])
q = [0] * (len(a) - len(b) + 1)
while ulong_cmp(a, ulong_mul(b, low)) >= 0:
q = ulong_add(q, low)
a = ulong_sub(a, ulong_mul(b, low))
ulong_unpad_(q)
return q, a
def ulong_floordivi(a: list, b: int):
# b > 0
return ulong_divmodi(a, b)[0]
def ulong_muli(a: list, b: int):
# b >= 0
res = [0] * len(a)
carry = 0
for i in range(len(a)):
carry += a[i] * b
res[i] = carry & PyLong_MASK
carry >>= PyLong_SHIFT
if carry > 0:
res.append(carry)
return res
def ulong_mul(a: list, b: list):
N = len(a) + len(b)
# use grade-school multiplication
res = [0] * N
for i in range(len(a)):
carry = 0
for j in range(len(b)):
carry += res[i+j] + a[i] * b[j]
res[i+j] = carry & PyLong_MASK
carry >>= PyLong_SHIFT
res[i+len(b)] = carry
ulong_unpad_(res)
return res
def ulong_powi(a: list, b: int):
# b >= 0
if b == 0: return [1]
res = [1]
while b:
if b & 1:
res = ulong_mul(res, a)
a = ulong_mul(a, a)
b >>= 1
return res
def ulong_repr(x: list) -> str:
res = []
while len(x)>1 or x[0]>0: # non-zero
x, r = ulong_divmodi(x, PyLong_DECIMAL_BASE)
res.append(str(r).zfill(PyLong_DECIMAL_SHIFT))
res.reverse()
s = ''.join(res)
if len(s) == 0: return '0'
if len(s) > 1: s = s.lstrip('0')
return s
def ulong_fromstr(s: str):
if s[-1] == 'L':
s = s[:-1]
res, base = [0], [1]
if s[0] == '-':
sign = -1
s = s[1:]
else:
sign = 1
s = s[::-1]
for c in s:
c = ord(c) - 48
assert 0 <= c <= 9
res = ulong_add(res, ulong_muli(base, c))
base = ulong_muli(base, 10)
return res, sign
class long:
def __init__(self, x):
if type(x) is tuple:
self.digits, self.sign = x
elif type(x) is int:
self.digits, self.sign = ulong_fromint(x)
elif type(x) is float:
self.digits, self.sign = ulong_fromint(int(x))
elif type(x) is str:
self.digits, self.sign = ulong_fromstr(x)
elif type(x) is long:
self.digits, self.sign = x.digits.copy(), x.sign
else:
raise TypeError('expected int or str')
def __len__(self):
return len(self.digits)
def __add__(self, other):
if type(other) is int:
other = long(other)
elif type(other) is not long:
return NotImplemented
if self.sign == other.sign:
return long((ulong_add(self.digits, other.digits), self.sign))
else:
cmp = ulong_cmp(self.digits, other.digits)
if cmp == 0:
return long(0)
if cmp > 0:
return long((ulong_sub(self.digits, other.digits), self.sign))
else:
return long((ulong_sub(other.digits, self.digits), other.sign))
def __radd__(self, other):
return self.__add__(other)
def __sub__(self, other):
if type(other) is int:
other = long(other)
elif type(other) is not long:
return NotImplemented
if self.sign != other.sign:
return long((ulong_add(self.digits, other.digits), self.sign))
cmp = ulong_cmp(self.digits, other.digits)
if cmp == 0:
return long(0)
if cmp > 0:
return long((ulong_sub(self.digits, other.digits), self.sign))
else:
return long((ulong_sub(other.digits, self.digits), -other.sign))
def __rsub__(self, other):
if type(other) is int:
other = long(other)
elif type(other) is not long:
return NotImplemented
return other.__sub__(self)
def __mul__(self, other):
if type(other) is int:
return long((
ulong_muli(self.digits, abs(other)),
self.sign * (1 if other >= 0 else -1)
))
elif type(other) is long:
return long((
ulong_mul(self.digits, other.digits),
self.sign * other.sign
))
return NotImplemented
def __rmul__(self, other):
return self.__mul__(other)
#######################################################
def __divmod__(self, other):
if type(other) is int:
assert self.sign == 1 and other > 0
q, r = ulong_divmodi(self.digits, other)
return long((q, 1)), r
if type(other) is long:
assert self.sign == 1 and other.sign == 1
q, r = ulong_divmod(self.digits, other.digits)
assert len(other)>1 or other.digits[0]>0
return long((q, 1)), long((r, 1))
raise NotImplementedError
def __floordiv__(self, other):
return self.__divmod__(other)[0]
def __mod__(self, other):
return self.__divmod__(other)[1]
def __pow__(self, other: int):
assert type(other) is int and other >= 0
if self.sign == -1 and other & 1:
sign = -1
else:
sign = 1
return long((ulong_powi(self.digits, other), sign))
def __lshift__(self, other: int):
assert type(other) is int and other >= 0
x = self.digits.copy()
q, r = divmod(other, PyLong_SHIFT)
x = [0]*q + x
for _ in range(r): x = ulong_muli(x, 2)
return long((x, self.sign))
def __rshift__(self, other: int):
assert type(other) is int and other >= 0
x = self.digits.copy()
q, r = divmod(other, PyLong_SHIFT)
x = x[q:]
if not x: return long(0)
for _ in range(r): x = ulong_floordivi(x, 2)
return long((x, self.sign))
def __neg__(self):
return long((self.digits, -self.sign))
def __cmp__(self, other):
if type(other) is int:
other = long(other)
elif type(other) is not long:
return NotImplemented
if self.sign > other.sign:
return 1
elif self.sign < other.sign:
return -1
else:
return ulong_cmp(self.digits, other.digits)
def __eq__(self, other):
return self.__cmp__(other) == 0
def __lt__(self, other):
return self.__cmp__(other) < 0
def __le__(self, other):
return self.__cmp__(other) <= 0
def __gt__(self, other):
return self.__cmp__(other) > 0
def __ge__(self, other):
return self.__cmp__(other) >= 0
def __repr__(self):
prefix = '-' if self.sign < 0 else ''
return prefix + ulong_repr(self.digits) + 'L'

View File

@ -174,13 +174,10 @@ def help(obj):
if obj.__doc__: if obj.__doc__:
print(obj.__doc__) print(obj.__doc__)
def complex(*args, **kwargs): def complex(real, imag=0):
import cmath import cmath
return cmath.complex(*args, **kwargs) return cmath.complex(real, imag)
def long(*args, **kwargs):
import _long
return _long.long(*args, **kwargs)
class set: class set:
def __init__(self, iterable=None): def __init__(self, iterable=None):

View File

@ -15,7 +15,6 @@ def Counter(iterable: Iterable[T]):
class defaultdict(dict): class defaultdict(dict):
def __init__(self, default_factory, *args): def __init__(self, default_factory, *args):
super().__init__(*args) super().__init__(*args)
_enable_instance_dict(self)
self.default_factory = default_factory self.default_factory = default_factory
def __missing__(self, key): def __missing__(self, key):
@ -133,7 +132,7 @@ class deque(Generic[T]):
def __eq__(self, other: object) -> bool: def __eq__(self, other: object) -> bool:
if not isinstance(other, deque): if not isinstance(other, deque):
return False return NotImplemented
if len(self) != len(other): if len(self) != len(other):
return False return False
for x, y in zip(self, other): for x, y in zip(self, other):
@ -141,6 +140,11 @@ class deque(Generic[T]):
return False return False
return True return True
def __ne__(self, other: object) -> bool:
if not isinstance(other, deque):
return NotImplemented
return not self == other
def __repr__(self) -> str: def __repr__(self) -> str:
return f"deque({list(self)!r})" return f"deque({list(self)!r})"

View File

@ -22,7 +22,7 @@ class _Pickler:
name = t.__name__ name = t.__name__
mod = t.__module__ mod = t.__module__
if mod is not None: if mod is not None:
name = mod.__path__ + _MOD_T_SEP + name name = mod + _MOD_T_SEP + name
return name return name
def wrap(self, o): def wrap(self, o):

View File

@ -4,7 +4,7 @@ python prebuild.py
SRC=$(find src/ -name "*.c") SRC=$(find src/ -name "*.c")
gcc -pg -Og -std=c11 -Wfatal-errors -o main $SRC src2/main.c -Iinclude gcc -pg -Og -std=c11 -Wfatal-errors -o main $SRC src2/main.c -Iinclude -lm -DNDEBUG -flto
./main benchmarks/fib.py ./main benchmarks/fib.py
gprof main gmon.out > gprof.txt gprof main gmon.out > gprof.txt
rm gmon.out rm gmon.out

File diff suppressed because one or more lines are too long

View File

@ -17,7 +17,7 @@ void py_Name__initialize() {
} }
c11_vector__ctor(&_r_interned, sizeof(c11_sv)); c11_vector__ctor(&_r_interned, sizeof(c11_sv));
#define MAGIC_METHOD(x) assert(x == py_name(#x)); #define MAGIC_METHOD(x) if(x != py_name(#x)) abort();
#include "pocketpy/xmacros/magics.h" #include "pocketpy/xmacros/magics.h"
#undef MAGIC_METHOD #undef MAGIC_METHOD
} }

View File

@ -334,7 +334,7 @@ void Literal0Expr__emit_(Expr* self_, Ctx* ctx) {
case TK_TRUE: opcode = OP_LOAD_TRUE; break; case TK_TRUE: opcode = OP_LOAD_TRUE; break;
case TK_FALSE: opcode = OP_LOAD_FALSE; break; case TK_FALSE: opcode = OP_LOAD_FALSE; break;
case TK_DOTDOTDOT: opcode = OP_LOAD_ELLIPSIS; break; case TK_DOTDOTDOT: opcode = OP_LOAD_ELLIPSIS; break;
default: assert(false); default: c11__unreachedable();
} }
Ctx__emit_(ctx, opcode, BC_NOARG, self->line); Ctx__emit_(ctx, opcode, BC_NOARG, self->line);
} }
@ -647,8 +647,8 @@ static void _load_expr(Ctx* ctx, c11_sv expr, int line) {
} }
c11_string* source = c11_string__new2(expr.data, expr.size); c11_string* source = c11_string__new2(expr.data, expr.size);
bool ok = py_compile(source->data, "<f-string>", EVAL_MODE, false); bool ok = py_compile(source->data, "<f-string>", EVAL_MODE, true);
if(!ok){ if(!ok) {
py_printexc(); py_printexc();
c11__abort("f-string: invalid expression"); c11__abort("f-string: invalid expression");
} }
@ -1662,12 +1662,6 @@ static Error* exprLiteral(Compiler* self) {
return NULL; return NULL;
} }
static Error* exprLong(Compiler* self) {
c11_sv sv = Token__sv(prev());
Ctx__s_push(ctx(), (Expr*)RawStringExpr__new(prev()->line, sv, OP_BUILD_LONG));
return NULL;
}
static Error* exprBytes(Compiler* self) { static Error* exprBytes(Compiler* self) {
c11_sv sv = c11_string__sv(prev()->value._str); c11_sv sv = c11_string__sv(prev()->value._str);
Ctx__s_push(ctx(), (Expr*)RawStringExpr__new(prev()->line, sv, OP_BUILD_BYTES)); Ctx__s_push(ctx(), (Expr*)RawStringExpr__new(prev()->line, sv, OP_BUILD_BYTES));
@ -2836,7 +2830,6 @@ const static PrattRule rules[TK__COUNT__] = {
[TK_NUM] = { exprLiteral, }, [TK_NUM] = { exprLiteral, },
[TK_STR] = { exprLiteral, }, [TK_STR] = { exprLiteral, },
[TK_FSTR] = { exprFString, }, [TK_FSTR] = { exprFString, },
[TK_LONG] = { exprLong, },
[TK_IMAG] = { exprImag, }, [TK_IMAG] = { exprImag, },
[TK_BYTES] = { exprBytes, }, [TK_BYTES] = { exprBytes, },
[TK_LBRACE] = { exprMap }, [TK_LBRACE] = { exprMap },

View File

@ -8,17 +8,17 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#define is_raw_string_used(t) ((t) == TK_ID || (t) == TK_LONG) #define is_raw_string_used(t) ((t) == TK_ID)
typedef struct Lexer{ typedef struct Lexer {
SourceData_ src; SourceData_ src;
const char* token_start; const char* token_start;
const char* curr_char; const char* curr_char;
int current_line; int current_line;
int brackets_level; int brackets_level;
c11_vector/*T=Token*/ nexts; c11_vector /*T=Token*/ nexts;
c11_vector/*T=int*/ indents; c11_vector /*T=int*/ indents;
} Lexer; } Lexer;
typedef struct TokenDeserializer { typedef struct TokenDeserializer {
@ -34,10 +34,9 @@ int TokenDeserializer__read_count(TokenDeserializer* self);
int64_t TokenDeserializer__read_uint(TokenDeserializer* self, char c); int64_t TokenDeserializer__read_uint(TokenDeserializer* self, char c);
double TokenDeserializer__read_float(TokenDeserializer* self, char c); double TokenDeserializer__read_float(TokenDeserializer* self, char c);
const static TokenValue EmptyTokenValue; const static TokenValue EmptyTokenValue;
static void Lexer__ctor(Lexer* self, SourceData_ src){ static void Lexer__ctor(Lexer* self, SourceData_ src) {
PK_INCREF(src); PK_INCREF(src);
self->src = src; self->src = src;
self->curr_char = self->token_start = src->source->data; self->curr_char = self->token_start = src->source->data;
@ -47,20 +46,20 @@ static void Lexer__ctor(Lexer* self, SourceData_ src){
c11_vector__ctor(&self->indents, sizeof(int)); c11_vector__ctor(&self->indents, sizeof(int));
} }
static void Lexer__dtor(Lexer* self){ static void Lexer__dtor(Lexer* self) {
PK_DECREF(self->src); PK_DECREF(self->src);
c11_vector__dtor(&self->nexts); c11_vector__dtor(&self->nexts);
c11_vector__dtor(&self->indents); c11_vector__dtor(&self->indents);
} }
static char eatchar(Lexer* self){ static char eatchar(Lexer* self) {
char c = *self->curr_char; char c = *self->curr_char;
assert(c != '\n'); // eatchar() cannot consume a newline assert(c != '\n'); // eatchar() cannot consume a newline
self->curr_char++; self->curr_char++;
return c; return c;
} }
static char eatchar_include_newline(Lexer* self){ static char eatchar_include_newline(Lexer* self) {
char c = *self->curr_char; char c = *self->curr_char;
self->curr_char++; self->curr_char++;
if(c == '\n') { if(c == '\n') {
@ -70,7 +69,7 @@ static char eatchar_include_newline(Lexer* self){
return c; return c;
} }
static int eat_spaces(Lexer* self){ static int eat_spaces(Lexer* self) {
int count = 0; int count = 0;
while(true) { while(true) {
switch(*self->curr_char) { switch(*self->curr_char) {
@ -82,13 +81,13 @@ static int eat_spaces(Lexer* self){
} }
} }
static bool matchchar(Lexer* self, char c){ static bool matchchar(Lexer* self, char c) {
if(*self->curr_char != c) return false; if(*self->curr_char != c) return false;
eatchar_include_newline(self); eatchar_include_newline(self);
return true; return true;
} }
static bool match_n_chars(Lexer* self, int n, char c0){ static bool match_n_chars(Lexer* self, int n, char c0) {
const char* c = self->curr_char; const char* c = self->curr_char;
for(int i = 0; i < n; i++) { for(int i = 0; i < n; i++) {
if(*c == '\0') return false; if(*c == '\0') return false;
@ -100,14 +99,14 @@ static bool match_n_chars(Lexer* self, int n, char c0){
return true; return true;
} }
static void skip_line_comment(Lexer* self){ static void skip_line_comment(Lexer* self) {
while(*self->curr_char) { while(*self->curr_char) {
if(*self->curr_char == '\n') return; if(*self->curr_char == '\n') return;
eatchar(self); eatchar(self);
} }
} }
static void add_token_with_value(Lexer* self, TokenIndex type, TokenValue value){ static void add_token_with_value(Lexer* self, TokenIndex type, TokenValue value) {
switch(type) { switch(type) {
case TK_LBRACE: case TK_LBRACE:
case TK_LBRACKET: case TK_LBRACKET:
@ -118,11 +117,11 @@ static void add_token_with_value(Lexer* self, TokenIndex type, TokenValue value)
default: break; default: break;
} }
Token token = {type, Token token = {type,
self->token_start, self->token_start,
(int)(self->curr_char - self->token_start), (int)(self->curr_char - self->token_start),
self->current_line - ((type == TK_EOL) ? 1 : 0), self->current_line - ((type == TK_EOL) ? 1 : 0),
self->brackets_level, self->brackets_level,
value}; value};
// handle "not in", "is not", "yield from" // handle "not in", "is not", "yield from"
if(self->nexts.count > 0) { if(self->nexts.count > 0) {
Token* back = &c11_vector__back(Token, &self->nexts); Token* back = &c11_vector__back(Token, &self->nexts);
@ -142,34 +141,42 @@ static void add_token_with_value(Lexer* self, TokenIndex type, TokenValue value)
} }
} }
static void add_token(Lexer* self, TokenIndex type){ static void add_token(Lexer* self, TokenIndex type) {
add_token_with_value(self, type, EmptyTokenValue); add_token_with_value(self, type, EmptyTokenValue);
} }
static void add_token_2(Lexer* self, char c, TokenIndex one, TokenIndex two){ static void add_token_2(Lexer* self, char c, TokenIndex one, TokenIndex two) {
if(matchchar(self, c)) if(matchchar(self, c))
add_token(self, two); add_token(self, two);
else else
add_token(self, one); add_token(self, one);
} }
static bool eat_indentation(Lexer* self){ static bool eat_indentation(Lexer* self) {
if(self->brackets_level > 0) return true; if(self->brackets_level > 0) return true;
int spaces = eat_spaces(self); int spaces = eat_spaces(self);
if(*self->curr_char == '#') skip_line_comment(self); if(*self->curr_char == '#') skip_line_comment(self);
if(*self->curr_char == '\0' || *self->curr_char == '\n'){ if(*self->curr_char == '\0' || *self->curr_char == '\n') { return true; }
return true;
}
// https://docs.python.org/3/reference/lexical_analysis.html#indentation // https://docs.python.org/3/reference/lexical_analysis.html#indentation
int indents_back = c11_vector__back(int, &self->indents); int indents_back = c11_vector__back(int, &self->indents);
if(spaces > indents_back) { if(spaces > indents_back) {
c11_vector__push(int, &self->indents, spaces); c11_vector__push(int, &self->indents, spaces);
Token t = {TK_INDENT, self->token_start, 0, self->current_line, self->brackets_level, EmptyTokenValue}; Token t = {TK_INDENT,
self->token_start,
0,
self->current_line,
self->brackets_level,
EmptyTokenValue};
c11_vector__push(Token, &self->nexts, t); c11_vector__push(Token, &self->nexts, t);
} else if(spaces < indents_back) { } else if(spaces < indents_back) {
do { do {
c11_vector__pop(&self->indents); c11_vector__pop(&self->indents);
Token t = {TK_DEDENT, self->token_start, 0, self->current_line, self->brackets_level, EmptyTokenValue}; Token t = {TK_DEDENT,
self->token_start,
0,
self->current_line,
self->brackets_level,
EmptyTokenValue};
c11_vector__push(Token, &self->nexts, t); c11_vector__push(Token, &self->nexts, t);
indents_back = c11_vector__back(int, &self->indents); indents_back = c11_vector__back(int, &self->indents);
} while(spaces < indents_back); } while(spaces < indents_back);
@ -178,28 +185,26 @@ static bool eat_indentation(Lexer* self){
return true; return true;
} }
static bool is_possible_number_char(char c){ static bool is_possible_number_char(char c) {
switch(c) { switch(c) {
// clang-format off // clang-format off
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
case '.': case 'L': case 'x': case 'o': case 'j': case '.': case 'x': case 'o': case 'j':
return true; return true;
default: return false; default: return false;
// clang-format on // clang-format on
} }
} }
/******************************/ /******************************/
static Error* SyntaxError(Lexer* self, const char* fmt, ...){ static Error* SyntaxError(Lexer* self, const char* fmt, ...) {
Error* err = malloc(sizeof(Error)); Error* err = malloc(sizeof(Error));
err->src = self->src; err->src = self->src;
PK_INCREF(self->src); PK_INCREF(self->src);
err->lineno = self->current_line; err->lineno = self->current_line;
if(*self->curr_char == '\n') { if(*self->curr_char == '\n') { err->lineno--; }
err->lineno--;
}
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
vsnprintf(err->msg, sizeof(err->msg), fmt, args); vsnprintf(err->msg, sizeof(err->msg), fmt, args);
@ -207,7 +212,7 @@ static Error* SyntaxError(Lexer* self, const char* fmt, ...){
return err; return err;
} }
static Error* eat_name(Lexer* self){ static Error* eat_name(Lexer* self) {
self->curr_char--; self->curr_char--;
while(true) { while(true) {
unsigned char c = *self->curr_char; unsigned char c = *self->curr_char;
@ -236,9 +241,9 @@ static Error* eat_name(Lexer* self){
value |= (b & 0b00111111) << (6 * (u8bytes - k - 1)); value |= (b & 0b00111111) << (6 * (u8bytes - k - 1));
} }
} }
if(c11__is_unicode_Lo_char(value)){ if(c11__is_unicode_Lo_char(value)) {
self->curr_char += u8bytes; self->curr_char += u8bytes;
}else{ } else {
break; break;
} }
} }
@ -249,10 +254,10 @@ static Error* eat_name(Lexer* self){
const char** KW_BEGIN = TokenSymbols + TK_FALSE; const char** KW_BEGIN = TokenSymbols + TK_FALSE;
int KW_COUNT = TK__COUNT__ - TK_FALSE; int KW_COUNT = TK__COUNT__ - TK_FALSE;
#define less(a, b) (c11_sv__cmp2(b, a) > 0) #define less(a, b) (c11_sv__cmp2(b, a) > 0)
int out; int out;
c11__lower_bound(const char*, KW_BEGIN, KW_COUNT, name, less, &out); c11__lower_bound(const char*, KW_BEGIN, KW_COUNT, name, less, &out);
#undef less #undef less
if(out != KW_COUNT && c11__sveq2(name, KW_BEGIN[out])) { if(out != KW_COUNT && c11__sveq2(name, KW_BEGIN[out])) {
add_token(self, (TokenIndex)(out + TK_FALSE)); add_token(self, (TokenIndex)(out + TK_FALSE));
@ -276,9 +281,7 @@ static Error* eat_string_until(Lexer* self, char quote, bool raw, c11_string** o
} }
break; break;
} }
if(c == '\0') { if(c == '\0') { return SyntaxError(self, "EOL while scanning string literal"); }
return SyntaxError(self, "EOL while scanning string literal");
}
if(c == '\n') { if(c == '\n') {
if(!quote3) if(!quote3)
return SyntaxError(self, "EOL while scanning string literal"); return SyntaxError(self, "EOL while scanning string literal");
@ -314,36 +317,33 @@ static Error* eat_string_until(Lexer* self, char quote, bool raw, c11_string** o
return NULL; return NULL;
} }
enum StringType { enum StringType { NORMAL_STRING, RAW_STRING, F_STRING, NORMAL_BYTES };
NORMAL_STRING,
RAW_STRING,
F_STRING,
NORMAL_BYTES
};
static Error* eat_string(Lexer* self, char quote, enum StringType type){ static Error* eat_string(Lexer* self, char quote, enum StringType type) {
c11_string* s; c11_string* s;
Error* err = eat_string_until(self, quote, type == RAW_STRING, &s); Error* err = eat_string_until(self, quote, type == RAW_STRING, &s);
if(err) return err; if(err) return err;
TokenValue value = {TokenValue_STR, ._str = s}; TokenValue value = {TokenValue_STR, ._str = s};
if(type == F_STRING) { if(type == F_STRING) {
add_token_with_value(self, TK_FSTR, value); add_token_with_value(self, TK_FSTR, value);
}else if(type == NORMAL_BYTES) { } else if(type == NORMAL_BYTES) {
add_token_with_value(self, TK_BYTES, value); add_token_with_value(self, TK_BYTES, value);
}else{ } else {
add_token_with_value(self, TK_STR, value); add_token_with_value(self, TK_STR, value);
} }
return NULL; return NULL;
} }
static Error* eat_number(Lexer* self){ static Error* eat_number(Lexer* self) {
const char* i = self->token_start; const char* i = self->token_start;
while(is_possible_number_char(*i)) i++; while(is_possible_number_char(*i))
i++;
bool is_scientific_notation = false; bool is_scientific_notation = false;
if(*(i - 1) == 'e' && (*i == '+' || *i == '-')) { if(*(i - 1) == 'e' && (*i == '+' || *i == '-')) {
i++; i++;
while(isdigit(*i) || *i == 'j') i++; while(isdigit(*i) || *i == 'j')
i++;
is_scientific_notation = true; is_scientific_notation = true;
} }
@ -351,21 +351,12 @@ static Error* eat_number(Lexer* self){
self->curr_char = i; self->curr_char = i;
if(text.data[0] != '.' && !is_scientific_notation) { if(text.data[0] != '.' && !is_scientific_notation) {
// try long
if(i[-1] == 'L') {
add_token(self, TK_LONG);
return NULL;
}
// try integer // try integer
TokenValue value = {.index = TokenValue_I64}; TokenValue value = {.index = TokenValue_I64};
switch(c11__parse_uint(text, &value._i64, -1)) { switch(c11__parse_uint(text, &value._i64, -1)) {
case IntParsing_SUCCESS: case IntParsing_SUCCESS: add_token_with_value(self, TK_NUM, value); return NULL;
add_token_with_value(self, TK_NUM, value); case IntParsing_OVERFLOW: return SyntaxError(self, "int literal is too large");
return NULL; case IntParsing_FAILURE: break; // do nothing
case IntParsing_OVERFLOW:
return SyntaxError(self, "int literal is too large");
case IntParsing_FAILURE:
break; // do nothing
} }
} }
@ -374,7 +365,7 @@ static Error* eat_number(Lexer* self){
char* p_end; char* p_end;
float_out = strtod(text.data, &p_end); float_out = strtod(text.data, &p_end);
if(p_end == text.data + text.size){ if(p_end == text.data + text.size) {
TokenValue value = {.index = TokenValue_F64, ._f64 = float_out}; TokenValue value = {.index = TokenValue_F64, ._f64 = float_out};
add_token_with_value(self, TK_NUM, value); add_token_with_value(self, TK_NUM, value);
return NULL; return NULL;
@ -389,7 +380,7 @@ static Error* eat_number(Lexer* self){
return SyntaxError(self, "invalid number literal"); return SyntaxError(self, "invalid number literal");
} }
static Error* lex_one_token(Lexer* self, bool* eof){ static Error* lex_one_token(Lexer* self, bool* eof) {
*eof = false; *eof = false;
while(*self->curr_char) { while(*self->curr_char) {
self->token_start = self->curr_char; self->token_start = self->curr_char;
@ -474,9 +465,9 @@ static Error* lex_one_token(Lexer* self, bool* eof){
return NULL; return NULL;
} }
case '!': case '!':
if(matchchar(self, '=')){ if(matchchar(self, '=')) {
add_token(self, TK_NE); add_token(self, TK_NE);
}else{ } else {
Error* err = SyntaxError(self, "expected '=' after '!'"); Error* err = SyntaxError(self, "expected '=' after '!'");
if(err) return err; if(err) return err;
} }
@ -499,7 +490,7 @@ static Error* lex_one_token(Lexer* self, bool* eof){
case '\t': eat_spaces(self); break; case '\t': eat_spaces(self); break;
case '\n': { case '\n': {
add_token(self, TK_EOL); add_token(self, TK_EOL);
if(!eat_indentation(self)){ if(!eat_indentation(self)) {
return SyntaxError(self, "unindent does not match any outer indentation level"); return SyntaxError(self, "unindent does not match any outer indentation level");
} }
return NULL; return NULL;
@ -542,7 +533,7 @@ static Error* from_precompiled(Lexer* self) {
if(c11_sv__cmp2(version, PK_VERSION) != 0) { if(c11_sv__cmp2(version, PK_VERSION) != 0) {
return SyntaxError(self, "precompiled version mismatch"); return SyntaxError(self, "precompiled version mismatch");
} }
if(TokenDeserializer__read_uint(&deserializer, '\n') != (int64_t)self->src->mode){ if(TokenDeserializer__read_uint(&deserializer, '\n') != (int64_t)self->src->mode) {
return SyntaxError(self, "precompiled mode mismatch"); return SyntaxError(self, "precompiled mode mismatch");
} }
@ -580,7 +571,7 @@ static Error* from_precompiled(Lexer* self) {
t.brackets_level = (int)TokenDeserializer__read_uint(&deserializer, ','); t.brackets_level = (int)TokenDeserializer__read_uint(&deserializer, ',');
} }
char type = (*deserializer.curr++); // read_char char type = (*deserializer.curr++); // read_char
switch(type) { switch(type) {
case 'I': { case 'I': {
int64_t res = TokenDeserializer__read_uint(&deserializer, '\n'); int64_t res = TokenDeserializer__read_uint(&deserializer, '\n');
@ -594,16 +585,14 @@ static Error* from_precompiled(Lexer* self) {
c11_string* res = TokenDeserializer__read_string_from_hex(&deserializer, '\n'); c11_string* res = TokenDeserializer__read_string_from_hex(&deserializer, '\n');
t.value = (TokenValue){TokenValue_STR, ._str = res}; t.value = (TokenValue){TokenValue_STR, ._str = res};
} break; } break;
default: default: t.value = EmptyTokenValue; break;
t.value = EmptyTokenValue;
break;
} }
c11_vector__push(Token, &self->nexts, t); c11_vector__push(Token, &self->nexts, t);
} }
return NULL; return NULL;
} }
Error* Lexer__process(SourceData_ src, TokenArray* out_tokens){ Error* Lexer__process(SourceData_ src, TokenArray* out_tokens) {
Lexer lexer; Lexer lexer;
Lexer__ctor(&lexer, src); Lexer__ctor(&lexer, src);
@ -614,14 +603,15 @@ Error* Lexer__process(SourceData_ src, TokenArray* out_tokens){
return err; return err;
} }
// push initial tokens // push initial tokens
Token sof = {TK_SOF, lexer.token_start, 0, lexer.current_line, lexer.brackets_level, EmptyTokenValue}; Token sof =
{TK_SOF, lexer.token_start, 0, lexer.current_line, lexer.brackets_level, EmptyTokenValue};
c11_vector__push(Token, &lexer.nexts, sof); c11_vector__push(Token, &lexer.nexts, sof);
c11_vector__push(int, &lexer.indents, 0); c11_vector__push(int, &lexer.indents, 0);
bool eof = false; bool eof = false;
while(!eof) { while(!eof) {
void* err = lex_one_token(&lexer, &eof); void* err = lex_one_token(&lexer, &eof);
if(err){ if(err) {
Lexer__dtor(&lexer); Lexer__dtor(&lexer);
return err; return err;
} }
@ -635,7 +625,7 @@ Error* Lexer__process(SourceData_ src, TokenArray* out_tokens){
Error* Lexer__process_and_dump(SourceData_ src, c11_string** out) { Error* Lexer__process_and_dump(SourceData_ src, c11_string** out) {
assert(!src->is_precompiled); assert(!src->is_precompiled);
TokenArray nexts; // output tokens TokenArray nexts; // output tokens
Error* err = Lexer__process(src, &nexts); Error* err = Lexer__process(src, &nexts);
if(err) return err; if(err) return err;
@ -665,7 +655,7 @@ Error* Lexer__process_and_dump(SourceData_ src, c11_string** out) {
c11_sbuf__write_char(&ss, '\n'); c11_sbuf__write_char(&ss, '\n');
uint16_t index = 0; uint16_t index = 0;
for(int i=0; i<token_indices.count; i++){ for(int i = 0; i < token_indices.count; i++) {
c11_smallmap_s2n_KV* kv = c11__at(c11_smallmap_s2n_KV, &token_indices, i); c11_smallmap_s2n_KV* kv = c11__at(c11_smallmap_s2n_KV, &token_indices, i);
// L4: raw strings // L4: raw strings
c11_sbuf__write_cstrn(&ss, kv->key.data, kv->key.size); c11_sbuf__write_cstrn(&ss, kv->key.data, kv->key.size);
@ -683,27 +673,27 @@ Error* Lexer__process_and_dump(SourceData_ src, c11_string** out) {
c11_sbuf__write_char(&ss, ','); c11_sbuf__write_char(&ss, ',');
if(is_raw_string_used(token->type)) { if(is_raw_string_used(token->type)) {
uint16_t *p = c11_smallmap_s2n__try_get( uint16_t* p =
&token_indices, (c11_sv){token->start, token->length}); c11_smallmap_s2n__try_get(&token_indices, (c11_sv){token->start, token->length});
assert(p != NULL); assert(p != NULL);
c11_sbuf__write_int(&ss, (int)*p); c11_sbuf__write_int(&ss, (int)*p);
c11_sbuf__write_char(&ss, ','); c11_sbuf__write_char(&ss, ',');
} }
if(i > 0 && c11__getitem(Token, &nexts, i-1).line == token->line){ if(i > 0 && c11__getitem(Token, &nexts, i - 1).line == token->line) {
c11_sbuf__write_char(&ss, ','); c11_sbuf__write_char(&ss, ',');
}else{ } else {
c11_sbuf__write_int(&ss, token->line); c11_sbuf__write_int(&ss, token->line);
c11_sbuf__write_char(&ss, ','); c11_sbuf__write_char(&ss, ',');
} }
if(i > 0 && c11__getitem(Token, &nexts, i-1).brackets_level == token->brackets_level){ if(i > 0 && c11__getitem(Token, &nexts, i - 1).brackets_level == token->brackets_level) {
c11_sbuf__write_char(&ss, ','); c11_sbuf__write_char(&ss, ',');
}else{ } else {
c11_sbuf__write_int(&ss, token->brackets_level); c11_sbuf__write_int(&ss, token->brackets_level);
c11_sbuf__write_char(&ss, ','); c11_sbuf__write_char(&ss, ',');
} }
// visit token value // visit token value
switch(token->value.index){ switch(token->value.index) {
case TokenValue_EMPTY: break; case TokenValue_EMPTY: break;
case TokenValue_I64: case TokenValue_I64:
c11_sbuf__write_char(&ss, 'I'); c11_sbuf__write_char(&ss, 'I');
@ -716,7 +706,7 @@ Error* Lexer__process_and_dump(SourceData_ src, c11_string** out) {
case TokenValue_STR: { case TokenValue_STR: {
c11_sbuf__write_char(&ss, 'S'); c11_sbuf__write_char(&ss, 'S');
c11_sv sv = c11_string__sv(token->value._str); c11_sv sv = c11_string__sv(token->value._str);
for(int i=0; i<sv.size; i++){ for(int i = 0; i < sv.size; i++) {
c11_sbuf__write_hex(&ss, sv.data[i], false); c11_sbuf__write_hex(&ss, sv.data[i], false);
} }
break; break;
@ -729,46 +719,120 @@ Error* Lexer__process_and_dump(SourceData_ src, c11_string** out) {
return NULL; return NULL;
} }
void TokenArray__dtor(TokenArray *self){ void TokenArray__dtor(TokenArray* self) {
Token* data = self->data; Token* data = self->data;
for(int i=0; i<self->count; i++){ for(int i = 0; i < self->count; i++) {
if(data[i].value.index == TokenValue_STR){ if(data[i].value.index == TokenValue_STR) { c11_string__delete(data[i].value._str); }
c11_string__delete(data[i].value._str);
}
} }
c11_array__dtor(self); c11_array__dtor(self);
} }
const char* TokenSymbols[] = { const char* TokenSymbols[] = {
"@eof", "@eol", "@sof", "@eof",
"@id", "@num", "@str", "@fstr", "@long", "@bytes", "@imag", "@eol",
"@indent", "@dedent", "@sof",
"@id",
"@num",
"@str",
"@fstr",
"@bytes",
"@imag",
"@indent",
"@dedent",
// These 3 are compound keywords which are generated on the fly // These 3 are compound keywords which are generated on the fly
"is not", "not in", "yield from", "is not",
"not in",
"yield from",
/*****************************************/ /*****************************************/
"+", "+=", "-", "-=", // (INPLACE_OP - 1) can get '=' removed "+",
"*", "*=", "/", "/=", "//", "//=", "%", "%=", "+=",
"&", "&=", "|", "|=", "^", "^=", "-",
"<<", "<<=", ">>", ">>=", "-=", // (INPLACE_OP - 1) can get '=' removed
"*",
"*=",
"/",
"/=",
"//",
"//=",
"%",
"%=",
"&",
"&=",
"|",
"|=",
"^",
"^=",
"<<",
"<<=",
">>",
">>=",
/*****************************************/ /*****************************************/
"(", ")", "[", "]", "{", "}", "(",
".", "..", "...", ",", ":", ";", ")",
"**", "->", "#", "@", "[",
">", "<", "=", "==", "!=", ">=", "<=", "~", "]",
"{",
"}",
".",
"..",
"...",
",",
":",
";",
"**",
"->",
"#",
"@",
">",
"<",
"=",
"==",
"!=",
">=",
"<=",
"~",
/** KW_BEGIN **/ /** KW_BEGIN **/
// NOTE: These keywords should be sorted in ascending order!! // NOTE: These keywords should be sorted in ascending order!!
"False", "None", "True", "and", "as", "assert", "break", "class", "continue", "False",
"def", "del", "elif", "else", "except", "finally", "for", "from", "global", "None",
"if", "import", "in", "is", "lambda", "not", "or", "pass", "raise", "return", "True",
"try", "while", "with", "yield", "and",
"as",
"assert",
"break",
"class",
"continue",
"def",
"del",
"elif",
"else",
"except",
"finally",
"for",
"from",
"global",
"if",
"import",
"in",
"is",
"lambda",
"not",
"or",
"pass",
"raise",
"return",
"try",
"while",
"with",
"yield",
}; };
void TokenDeserializer__ctor(TokenDeserializer* self, const char* source){ void TokenDeserializer__ctor(TokenDeserializer* self, const char* source) {
self->curr = source; self->curr = source;
self->source = source; self->source = source;
} }
bool TokenDeserializer__match_char(TokenDeserializer* self, char c){ bool TokenDeserializer__match_char(TokenDeserializer* self, char c) {
if(*self->curr == c) { if(*self->curr == c) {
self->curr++; self->curr++;
return true; return true;
@ -776,16 +840,16 @@ bool TokenDeserializer__match_char(TokenDeserializer* self, char c){
return false; return false;
} }
c11_sv TokenDeserializer__read_string(TokenDeserializer* self, char c){ c11_sv TokenDeserializer__read_string(TokenDeserializer* self, char c) {
const char* start = self->curr; const char* start = self->curr;
while(*self->curr != c) while(*self->curr != c)
self->curr++; self->curr++;
c11_sv retval = {start, (int)(self->curr-start)}; c11_sv retval = {start, (int)(self->curr - start)};
self->curr++; // skip the delimiter self->curr++; // skip the delimiter
return retval; return retval;
} }
c11_string* TokenDeserializer__read_string_from_hex(TokenDeserializer* self, char c){ c11_string* TokenDeserializer__read_string_from_hex(TokenDeserializer* self, char c) {
c11_sv sv = TokenDeserializer__read_string(self, c); c11_sv sv = TokenDeserializer__read_string(self, c);
const char* s = sv.data; const char* s = sv.data;
c11_sbuf ss; c11_sbuf ss;
@ -810,13 +874,13 @@ c11_string* TokenDeserializer__read_string_from_hex(TokenDeserializer* self, cha
return c11_sbuf__submit(&ss); return c11_sbuf__submit(&ss);
} }
int TokenDeserializer__read_count(TokenDeserializer* self){ int TokenDeserializer__read_count(TokenDeserializer* self) {
assert(*self->curr == '='); assert(*self->curr == '=');
self->curr++; self->curr++;
return TokenDeserializer__read_uint(self, '\n'); return TokenDeserializer__read_uint(self, '\n');
} }
int64_t TokenDeserializer__read_uint(TokenDeserializer* self, char c){ int64_t TokenDeserializer__read_uint(TokenDeserializer* self, char c) {
int64_t out = 0; int64_t out = 0;
while(*self->curr != c) { while(*self->curr != c) {
out = out * 10 + (*self->curr - '0'); out = out * 10 + (*self->curr - '0');
@ -826,7 +890,7 @@ int64_t TokenDeserializer__read_uint(TokenDeserializer* self, char c){
return out; return out;
} }
double TokenDeserializer__read_float(TokenDeserializer* self, char c){ double TokenDeserializer__read_float(TokenDeserializer* self, char c) {
c11_sv sv = TokenDeserializer__read_string(self, c); c11_sv sv = TokenDeserializer__read_string(self, c);
// TODO: optimize this // TODO: optimize this
c11_string* nullterm = c11_string__new2(sv.data, sv.size); c11_string* nullterm = c11_string__new2(sv.data, sv.size);

View File

@ -89,6 +89,13 @@ FrameResult VM__run_top_frame(VM* self) {
pk_print_stack(self, frame, byte); pk_print_stack(self, frame, byte);
// #if PK_DEBUG
// if(py_checkexc()) {
// py_printexc();
// c11__abort("unhandled exception!");
// }
// #endif
switch((Opcode)byte.op) { switch((Opcode)byte.op) {
case OP_NO_OP: DISPATCH(); case OP_NO_OP: DISPATCH();
/*****************************************/ /*****************************************/
@ -451,17 +458,7 @@ FrameResult VM__run_top_frame(VM* self) {
TypeError("'%t' object does not support item deletion", SECOND()->type); TypeError("'%t' object does not support item deletion", SECOND()->type);
goto __ERROR; goto __ERROR;
} }
/*****************************************/ /*****************************************/
case OP_BUILD_LONG: {
// [x]
py_Ref f = py_getdict(&self->builtins, py_name("long"));
assert(f != NULL);
if(!py_call(f, 1, TOP())) goto __ERROR;
*TOP() = self->last_retval;
DISPATCH();
}
case OP_BUILD_IMAG: { case OP_BUILD_IMAG: {
// [x] // [x]
py_Ref f = py_getdict(&self->builtins, py_name("complex")); py_Ref f = py_getdict(&self->builtins, py_name("complex"));
@ -694,9 +691,9 @@ FrameResult VM__run_top_frame(VM* self) {
buf[n++] = *curr; buf[n++] = *curr;
} else { } else {
py_TValue* args = py_getslot(curr, 0); py_TValue* args = py_getslot(curr, 0);
int length; py_TValue* p;
py_TValue* p = pk_arrayview(args, &length); int length = pk_arrayview(args, &p);
if(p) { if(length != -1) {
for(int j = 0; j < length; j++) { for(int j = 0; j < length; j++) {
buf[n++] = p[j]; buf[n++] = p[j];
} }
@ -827,7 +824,7 @@ FrameResult VM__run_top_frame(VM* self) {
int res = py_import(path); int res = py_import(path);
if(res == -1) goto __ERROR; if(res == -1) goto __ERROR;
if(res == 0) { if(res == 0) {
ImportError("module '%s' not found", path); ImportError("No module named '%s'", path);
goto __ERROR; goto __ERROR;
} }
PUSH(py_retval()); PUSH(py_retval());
@ -838,9 +835,9 @@ FrameResult VM__run_top_frame(VM* self) {
NameDict* dict = PyObject__dict(TOP()->_obj); NameDict* dict = PyObject__dict(TOP()->_obj);
py_Ref all = NameDict__try_get(dict, __all__); py_Ref all = NameDict__try_get(dict, __all__);
if(all) { if(all) {
int length; py_TValue* p;
py_TValue* p = pk_arrayview(all, &length); int length = pk_arrayview(all, &p);
if(!p) { if(length == -1) {
TypeError("'__all__' must be a list or tuple, got '%t'", all->type); TypeError("'__all__' must be a list or tuple, got '%t'", all->type);
goto __ERROR; goto __ERROR;
} }
@ -872,10 +869,10 @@ FrameResult VM__run_top_frame(VM* self) {
DISPATCH(); DISPATCH();
} }
case OP_UNPACK_EX: { case OP_UNPACK_EX: {
int length; py_TValue* p;
py_TValue* p = pk_arrayview(TOP(), &length); int length = pk_arrayview(TOP(), &p);
if(!p) { if(length == -1) {
TypeError("expected list or tuple to unpack, got '%t'", TOP()->type); TypeError("expected list or tuple to unpack, got %t", TOP()->type);
goto __ERROR; goto __ERROR;
} }
int exceed = length - byte.arg; int exceed = length - byte.arg;
@ -1027,9 +1024,12 @@ FrameResult VM__run_top_frame(VM* self) {
} }
////////////////// //////////////////
case OP_FSTRING_EVAL: { case OP_FSTRING_EVAL: {
py_TValue* tmp = c11__at(py_TValue, &frame->co->consts, byte.arg); py_TValue* code = c11__at(py_TValue, &frame->co->consts, byte.arg);
assert(py_istype(tmp, tp_code)); assert(py_istype(code, tp_code));
if(!pk_exec(py_touserdata(tmp), frame->module)) goto __ERROR; py_newglobals(SP()++);
py_newlocals(SP()++);
PUSH(code);
if(!pk_exec(py_touserdata(code), frame->module)) goto __ERROR;
PUSH(py_retval()); PUSH(py_retval());
DISPATCH(); DISPATCH();
} }
@ -1100,11 +1100,15 @@ bool pk_stack_binaryop(VM* self, py_Name op, py_Name rop) {
} }
} }
// eq/ne op never fails // eq/ne op never fails
if(op == __eq__ || op == __ne__) { bool res = py_isidentical(SECOND(), TOP());
bool res = py_isidentical(SECOND(), TOP()); if(op == __eq__) {
py_newbool(py_retval(), res); py_newbool(py_retval(), res);
return true; return true;
} }
if(op == __ne__) {
py_newbool(py_retval(), !res);
return true;
}
return TypeError("unsupported operand type(s) for '%n'", op); return TypeError("unsupported operand type(s) for '%n'", op);
} }
@ -1118,9 +1122,9 @@ bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) {
} }
static bool stack_unpack_sequence(VM* self, uint16_t arg) { static bool stack_unpack_sequence(VM* self, uint16_t arg) {
int length; py_TValue* p;
py_TValue* p = pk_arrayview(TOP(), &length); int length = pk_arrayview(TOP(), &p);
if(!p) return TypeError("expected list or tuple to unpack, got '%t'", TOP()->type); if(length == -1) return TypeError("expected list or tuple to unpack, got %t", TOP()->type);
if(length != arg) return ValueError("expected %d values to unpack, got %d", arg, length); if(length != arg) return ValueError("expected %d values to unpack, got %d", arg, length);
POP(); POP();
for(int i = 0; i < length; i++) { for(int i = 0; i < length; i++) {

View File

@ -17,7 +17,7 @@ static char* pk_default_import_file(const char* path) {
long size = ftell(f); long size = ftell(f);
fseek(f, 0, SEEK_SET); fseek(f, 0, SEEK_SET);
char* buffer = malloc(size + 1); char* buffer = malloc(size + 1);
fread(buffer, 1, size, f); size = fread(buffer, 1, size, f);
buffer[size] = 0; buffer[size] = 0;
fclose(f); fclose(f);
return buffer; return buffer;
@ -195,6 +195,7 @@ void VM__ctor(VM* self) {
// add modules // add modules
pk__add_module_pkpy(); pk__add_module_pkpy();
pk__add_module_os(); pk__add_module_os();
pk__add_module_sys();
pk__add_module_math(); pk__add_module_math();
pk__add_module_dis(); pk__add_module_dis();
pk__add_module_random(); pk__add_module_random();
@ -571,7 +572,7 @@ static void mark_object(PyObject* obj) {
} }
py_TypeInfo* types = c11__at(py_TypeInfo, &pk_current_vm->types, obj->type); py_TypeInfo* types = c11__at(py_TypeInfo, &pk_current_vm->types, obj->type);
if(types->gc_mark) { types->gc_mark(PyObject__userdata(obj)); } if(types->gc_mark) types->gc_mark(PyObject__userdata(obj));
} }
void CodeObject__gc_mark(const CodeObject* self) { void CodeObject__gc_mark(const CodeObject* self) {
@ -590,6 +591,17 @@ void ManagedHeap__mark(ManagedHeap* self) {
for(py_TValue* p = vm->stack.begin; p != vm->stack.end; p++) { for(py_TValue* p = vm->stack.begin; p != vm->stack.end; p++) {
pk__mark_value(p); pk__mark_value(p);
} }
// mark magic slots
py_TypeInfo* types = vm->types.data;
int types_length = vm->types.count;
// 0-th type is placeholder
for(int i = 1; i < types_length; i++) {
for(int j = 0; j <= __missing__; j++) {
py_TValue* slot = types[i].magic + j;
if(py_isnil(slot)) continue;
pk__mark_value(slot);
}
}
// mark frame // mark frame
for(Frame* frame = vm->top_frame; frame; frame = frame->f_back) { for(Frame* frame = vm->top_frame; frame; frame = frame->f_back) {
Frame__gc_mark(frame); Frame__gc_mark(frame);
@ -652,7 +664,8 @@ void pk_print_stack(VM* self, Frame* frame, Bytecode byte) {
} }
c11_string* stack_str = c11_sbuf__submit(&buf); c11_string* stack_str = c11_sbuf__submit(&buf);
printf("L%-3d: %-25s %-6d [%s]\n", printf("%s:%-3d: %-25s %-6d [%s]\n",
frame->co->src->filename->data,
Frame__lineno(frame), Frame__lineno(frame),
pk_opname(byte.op), pk_opname(byte.op),
byte.arg, byte.arg,

View File

@ -83,7 +83,6 @@ static bool math_isclose(int argc, py_Ref argv) {
ONE_ARG_FUNC(exp, exp) ONE_ARG_FUNC(exp, exp)
static bool math_log(int argc, py_Ref argv) { static bool math_log(int argc, py_Ref argv) {
PY_CHECK_ARG_TYPE(0, tp_float);
double x; double x;
if(!py_castfloat(py_arg(0), &x)) return false; if(!py_castfloat(py_arg(0), &x)) return false;
if(argc == 1) { if(argc == 1) {

View File

@ -47,4 +47,8 @@ void pk__add_module_os() {
py_Ref mod = py_newmodule("os"); py_Ref mod = py_newmodule("os");
py_bindfunc(mod, "chdir", os_chdir); py_bindfunc(mod, "chdir", os_chdir);
py_bindfunc(mod, "getcwd", os_getcwd); py_bindfunc(mod, "getcwd", os_getcwd);
}
void pk__add_module_sys() {
py_Ref mod = py_newmodule("sys");
} }

View File

@ -195,9 +195,9 @@ static bool Random_randint(int argc, py_Ref argv) {
static bool Random_choice(int argc, py_Ref argv) { static bool Random_choice(int argc, py_Ref argv) {
PY_CHECK_ARGC(2); PY_CHECK_ARGC(2);
mt19937* ud = py_touserdata(py_arg(0)); mt19937* ud = py_touserdata(py_arg(0));
int length; py_TValue* p;
py_TValue* p = pk_arrayview(py_arg(1), &length); int length = pk_arrayview(py_arg(1), &p);
if(!p) return TypeError("choice(): argument must be a list or tuple"); if(length == -1) return TypeError("choice(): argument must be a list or tuple");
if(length == 0) return IndexError("cannot choose from an empty sequence"); if(length == 0) return IndexError("cannot choose from an empty sequence");
int index = mt19937__randint(ud, 0, length - 1); int index = mt19937__randint(ud, 0, length - 1);
py_assign(py_retval(), p + index); py_assign(py_retval(), p + index);
@ -206,9 +206,9 @@ static bool Random_choice(int argc, py_Ref argv) {
static bool Random_choices(int argc, py_Ref argv) { static bool Random_choices(int argc, py_Ref argv) {
mt19937* ud = py_touserdata(py_arg(0)); mt19937* ud = py_touserdata(py_arg(0));
int length; py_TValue* p;
py_TValue* p = pk_arrayview(py_arg(1), &length); int length = pk_arrayview(py_arg(1), &p);
if(!p) return TypeError("choices(): argument must be a list or tuple"); if(length == -1) return TypeError("choices(): argument must be a list or tuple");
if(length == 0) return IndexError("cannot choose from an empty sequence"); if(length == 0) return IndexError("cannot choose from an empty sequence");
py_Ref weights = py_arg(2); py_Ref weights = py_arg(2);
if(!py_checktype(py_arg(3), tp_int)) return false; if(!py_checktype(py_arg(3), tp_int)) return false;
@ -219,9 +219,9 @@ static bool Random_choices(int argc, py_Ref argv) {
for(int i = 0; i < length; i++) for(int i = 0; i < length; i++)
cum_weights[i] = i + 1; cum_weights[i] = i + 1;
} else { } else {
int wlen; py_TValue* w;
py_TValue* w = pk_arrayview(weights, &wlen); int wlen = pk_arrayview(weights, &w);
if(!w) { if(wlen == -1) {
free(cum_weights); free(cum_weights);
return TypeError("choices(): weights must be a list or tuple"); return TypeError("choices(): weights must be a list or tuple");
} }

View File

@ -179,6 +179,7 @@ int CodeObject__add_varname(CodeObject* self, py_Name name) {
} }
void Function__dtor(Function* self) { void Function__dtor(Function* self) {
// printf("%s() in %s freed!\n", self->decl->code.name->data, self->decl->code.src->filename->data);
PK_DECREF(self->decl); PK_DECREF(self->decl);
if(self->closure) NameDict__delete(self->closure); if(self->closure) NameDict__delete(self->closure);
} }

View File

@ -91,18 +91,22 @@ bool py_call(py_Ref f, int argc, py_Ref argv) {
} }
} }
#if PK_DEBUG
bool py_callcfunc(py_CFunction f, int argc, py_Ref argv) { bool py_callcfunc(py_CFunction f, int argc, py_Ref argv) {
py_StackRef p0 = py_peek(0); py_StackRef p0 = py_peek(0);
py_newnil(py_retval()); py_newnil(py_retval());
bool ok = f(argc, argv); bool ok = f(argc, argv);
if(!ok) return false; if(!ok) return false;
if(py_peek(0) != p0) if(py_peek(0) != p0) {
c11__abort("py_CFunction corrupts the stack! Did you forget to call `py_pop()`?"); c11__abort("py_CFunction corrupts the stack! Did you forget to call `py_pop()`?");
if(py_isnil(py_retval())) }
if(py_isnil(py_retval())) {
c11__abort( c11__abort(
"py_CFunction returns nothing! Did you forget to call `py_newnone(py_retval())`?"); "py_CFunction returns nothing! Did you forget to call `py_newnone(py_retval())`?");
}
return true; return true;
} }
#endif
bool py_vectorcall(uint16_t argc, uint16_t kwargc) { bool py_vectorcall(uint16_t argc, uint16_t kwargc) {
return VM__vectorcall(pk_current_vm, argc, kwargc, false) != RES_ERROR; return VM__vectorcall(pk_current_vm, argc, kwargc, false) != RES_ERROR;

View File

@ -21,15 +21,14 @@ void py_setglobal(py_Name name, py_Ref val) { py_setdict(&pk_current_vm->main, n
py_Ref py_newmodule(const char* path) { py_Ref py_newmodule(const char* path) {
ManagedHeap* heap = &pk_current_vm->heap; ManagedHeap* heap = &pk_current_vm->heap;
PyObject* obj = ManagedHeap__new(heap, tp_module, -1, 0);
py_Ref r0 = py_pushtmp(); py_Ref r0 = py_pushtmp();
py_Ref r1 = py_pushtmp(); py_Ref r1 = py_pushtmp();
*r0 = (py_TValue){ *r0 = (py_TValue){
.type = obj->type, .type = tp_module,
.is_ptr = true, .is_ptr = true,
._obj = obj, ._obj = ManagedHeap__new(heap, tp_module, -1, 0),
}; };
int last_dot = c11_sv__rindex((c11_sv){path, strlen(path)}, '.'); int last_dot = c11_sv__rindex((c11_sv){path, strlen(path)}, '.');
@ -144,11 +143,11 @@ int py_import(const char* path_cstr) {
return 0; return 0;
__SUCCESS: __SUCCESS:
py_push(py_newmodule(path_cstr)); do {
py_Ref mod = py_peek(-1); } while(0);
py_GlobalRef mod = py_newmodule(path_cstr);
bool ok = py_exec((const char*)data, filename->data, EXEC_MODE, mod); bool ok = py_exec((const char*)data, filename->data, EXEC_MODE, mod);
py_assign(py_retval(), mod); py_assign(py_retval(), mod);
py_pop();
c11_string__delete(filename); c11_string__delete(filename);
c11_string__delete(slashed_path); c11_string__delete(slashed_path);
@ -273,9 +272,9 @@ static bool builtins_round(int argc, py_Ref argv) {
} }
static bool builtins_print(int argc, py_Ref argv) { static bool builtins_print(int argc, py_Ref argv) {
int length; py_TValue* args;
py_TValue* args = pk_arrayview(argv, &length); int length = pk_arrayview(argv, &args);
assert(args != NULL); assert(length != -1);
c11_sv sep = py_tosv(py_arg(1)); c11_sv sep = py_tosv(py_arg(1));
c11_sv end = py_tosv(py_arg(2)); c11_sv end = py_tosv(py_arg(2));
c11_sbuf buf; c11_sbuf buf;
@ -322,6 +321,22 @@ static bool builtins_issubclass(int argc, py_Ref argv) {
return true; return true;
} }
static bool builtins_callable(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
bool res;
switch(argv->type) {
case tp_nativefunc: res = true; break;
case tp_function: res = true; break;
case tp_type: res = true; break;
case tp_boundmethod: res = true; break;
case tp_staticmethod: res = true; break;
case tp_classmethod: res = true; break;
default: res = py_tpfindmagic(argv->type, __call__); break;
}
py_newbool(py_retval(), res);
return true;
}
static bool builtins_getattr(int argc, py_Ref argv) { static bool builtins_getattr(int argc, py_Ref argv) {
PY_CHECK_ARG_TYPE(1, tp_str); PY_CHECK_ARG_TYPE(1, tp_str);
py_Name name = py_namev(py_tosv(py_arg(1))); py_Name name = py_namev(py_tosv(py_arg(1)));
@ -394,6 +409,16 @@ static bool builtins_ord(int argc, py_Ref argv) {
return true; return true;
} }
static bool builtins_id(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
if(argv->is_ptr) {
py_newint(py_retval(), (py_i64)argv->_obj);
} else {
py_newnone(py_retval());
}
return true;
}
static bool builtins_globals(int argc, py_Ref argv) { static bool builtins_globals(int argc, py_Ref argv) {
PY_CHECK_ARGC(0); PY_CHECK_ARGC(0);
py_newglobals(py_retval()); py_newglobals(py_retval());
@ -512,6 +537,15 @@ static bool builtins_compile(int argc, py_Ref argv) {
return py_compile(source, filename, compile_mode, true); return py_compile(source, filename, compile_mode, true);
} }
static bool builtins__import__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
PY_CHECK_ARG_TYPE(0, tp_str);
int res = py_import(py_tostr(argv));
if(res == -1) return false;
if(res) return true;
return ImportError("No module named '%s'", py_tostr(argv));
}
static bool NoneType__repr__(int argc, py_Ref argv) { static bool NoneType__repr__(int argc, py_Ref argv) {
py_newstr(py_retval(), "None"); py_newstr(py_retval(), "None");
return true; return true;
@ -544,6 +578,7 @@ py_TValue pk_builtins__register() {
py_bindfunc(builtins, "isinstance", builtins_isinstance); py_bindfunc(builtins, "isinstance", builtins_isinstance);
py_bindfunc(builtins, "issubclass", builtins_issubclass); py_bindfunc(builtins, "issubclass", builtins_issubclass);
py_bindfunc(builtins, "callable", builtins_callable);
py_bindfunc(builtins, "getattr", builtins_getattr); py_bindfunc(builtins, "getattr", builtins_getattr);
py_bindfunc(builtins, "setattr", builtins_setattr); py_bindfunc(builtins, "setattr", builtins_setattr);
@ -552,6 +587,7 @@ py_TValue pk_builtins__register() {
py_bindfunc(builtins, "chr", builtins_chr); py_bindfunc(builtins, "chr", builtins_chr);
py_bindfunc(builtins, "ord", builtins_ord); py_bindfunc(builtins, "ord", builtins_ord);
py_bindfunc(builtins, "id", builtins_id);
py_bindfunc(builtins, "globals", builtins_globals); py_bindfunc(builtins, "globals", builtins_globals);
py_bindfunc(builtins, "locals", builtins_locals); py_bindfunc(builtins, "locals", builtins_locals);
@ -559,10 +595,15 @@ py_TValue pk_builtins__register() {
py_bindfunc(builtins, "eval", builtins_eval); py_bindfunc(builtins, "eval", builtins_eval);
py_bindfunc(builtins, "compile", builtins_compile); py_bindfunc(builtins, "compile", builtins_compile);
py_bindfunc(builtins, "__import__", builtins__import__);
// some patches // some patches
py_bindmagic(tp_NoneType, __repr__, NoneType__repr__); py_bindmagic(tp_NoneType, __repr__, NoneType__repr__);
*py_tpgetmagic(tp_NoneType, __hash__) = *py_None;
py_bindmagic(tp_ellipsis, __repr__, ellipsis__repr__); py_bindmagic(tp_ellipsis, __repr__, ellipsis__repr__);
*py_tpgetmagic(tp_ellipsis, __hash__) = *py_None;
py_bindmagic(tp_NotImplementedType, __repr__, NotImplementedType__repr__); py_bindmagic(tp_NotImplementedType, __repr__, NotImplementedType__repr__);
*py_tpgetmagic(tp_NotImplementedType, __hash__) = *py_None;
return *builtins; return *builtins;
} }

View File

@ -11,32 +11,48 @@ typedef struct array_iterator {
int index; int index;
} array_iterator; } array_iterator;
py_TValue* pk_arrayview(py_Ref self, int* length) { int pk_arrayview(py_Ref self, py_TValue** p) {
if(self->type == tp_list) { if(self->type == tp_list) {
*length = py_list_len(self); *p = py_list_data(self);
return py_list_data(self); return py_list_len(self);
} }
if(self->type == tp_tuple) { if(self->type == tp_tuple) {
*length = py_tuple_len(self); *p = PyObject__slots(self->_obj);
return PyObject__slots(self->_obj); return py_tuple_len(self);
} }
return NULL; return -1;
} }
int pk_arrayequal(py_TValue* lhs, int lhs_length, py_TValue* rhs, int rhs_length) { bool pk_wrapper__arrayequal(py_Type type, int argc, py_Ref argv) {
if(lhs_length != rhs_length) return false; PY_CHECK_ARGC(2);
for(int i = 0; i < lhs_length; i++) { if(!py_istype(py_arg(1), type)) {
int res = py_equal(lhs + i, rhs + i); py_newnotimplemented(py_retval());
if(res == -1) return -1; return true;
if(!res) return false;
} }
py_TValue *p0, *p1;
int lhs_length = pk_arrayview(py_arg(0), &p0);
int rhs_length = pk_arrayview(py_arg(1), &p1);
assert(lhs_length != -1 && rhs_length != -1);
if(lhs_length != rhs_length) {
py_newbool(py_retval(), false);
return true;
}
for(int i = 0; i < lhs_length; i++) {
int res = py_equal(p0 + i, p1 + i);
if(res == -1) return false;
if(!res) {
py_newbool(py_retval(), false);
return true;
}
}
py_newbool(py_retval(), true);
return true; return true;
} }
bool pk_arrayiter(py_Ref val) { bool pk_arrayiter(py_Ref val) {
int length; py_TValue* p;
py_TValue* p = pk_arrayview(val, &length); int length = pk_arrayview(val, &p);
if(!p) return TypeError("expected list or tuple, got %t", val->type); if(length == -1) return TypeError("expected list or tuple, got %t", val->type);
array_iterator* ud = py_newobject(py_retval(), tp_array_iterator, 1, sizeof(array_iterator)); array_iterator* ud = py_newobject(py_retval(), tp_array_iterator, 1, sizeof(array_iterator));
ud->p = p; ud->p = p;
ud->length = length; ud->length = length;
@ -46,9 +62,9 @@ bool pk_arrayiter(py_Ref val) {
} }
bool pk_arraycontains(py_Ref self, py_Ref val) { bool pk_arraycontains(py_Ref self, py_Ref val) {
int length; py_TValue* p;
py_TValue* p = pk_arrayview(self, &length); int length = pk_arrayview(self, &p);
if(!p) return TypeError("expected list or tuple, got %t", self->type); if(length == -1) return TypeError("expected list or tuple, got %t", self->type);
for(int i = 0; i < length; i++) { for(int i = 0; i < length; i++) {
int res = py_equal(p + i, val); int res = py_equal(p + i, val);
if(res == -1) return false; if(res == -1) return false;

View File

@ -206,10 +206,18 @@ static DictEntry* DictIterator__next(DictIterator* self) {
/////////////////////////////// ///////////////////////////////
static bool dict__new__(int argc, py_Ref argv) { static bool dict__new__(int argc, py_Ref argv) {
py_newdict(py_retval()); py_Type cls = py_totype(argv);
int slots = cls == tp_dict ? 0 : -1;
Dict* ud = py_newobject(py_retval(), cls, slots, sizeof(Dict));
Dict__ctor(ud, 8);
return true; return true;
} }
void py_newdict(py_Ref out) {
Dict* ud = py_newobject(out, tp_dict, 0, sizeof(Dict));
Dict__ctor(ud, 8);
}
static bool dict__init__(int argc, py_Ref argv) { static bool dict__init__(int argc, py_Ref argv) {
py_newnone(py_retval()); py_newnone(py_retval());
if(argc > 2) return TypeError("dict.__init__() takes at most 2 arguments (%d given)", argc); if(argc > 2) return TypeError("dict.__init__() takes at most 2 arguments (%d given)", argc);
@ -239,6 +247,9 @@ static bool dict__getitem__(int argc, py_Ref argv) {
*py_retval() = entry->val; *py_retval() = entry->val;
return true; return true;
} }
// try __missing__
py_Ref missing = py_tpfindmagic(argv->type, __missing__);
if(missing) return py_call(missing, argc, argv);
return KeyError(py_arg(1)); return KeyError(py_arg(1));
} }
@ -495,11 +506,6 @@ py_Type pk_dict_items__register() {
////////////////////////// //////////////////////////
void py_newdict(py_Ref out) {
Dict* ud = py_newobject(out, tp_dict, 0, sizeof(Dict));
Dict__ctor(ud, 8);
}
py_Ref py_dict_getitem(py_Ref self, py_Ref key) { py_Ref py_dict_getitem(py_Ref self, py_Ref key) {
assert(py_isdict(self)); assert(py_isdict(self));
Dict* ud = py_touserdata(self); Dict* ud = py_touserdata(self);

View File

@ -75,18 +75,7 @@ static bool list__len__(int argc, py_Ref argv) {
} }
static bool list__eq__(int argc, py_Ref argv) { static bool list__eq__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2); return pk_wrapper__arrayequal(tp_list, argc, argv);
if(py_istype(py_arg(1), tp_list)) {
int length0, length1;
py_TValue* a0 = pk_arrayview(py_arg(0), &length0);
py_TValue* a1 = pk_arrayview(py_arg(1), &length1);
int res = pk_arrayequal(a0, length0, a1, length1);
if(res == -1) return false;
py_newbool(py_retval(), res);
} else {
py_newnotimplemented(py_retval());
}
return true;
} }
static bool list__ne__(int argc, py_Ref argv) { static bool list__ne__(int argc, py_Ref argv) {
@ -104,9 +93,9 @@ static bool list__new__(int argc, py_Ref argv) {
return true; return true;
} }
if(argc == 2) { if(argc == 2) {
int length; py_TValue* p;
py_TValue* p = pk_arrayview(py_arg(1), &length); int length = pk_arrayview(py_arg(1), &p);
if(p) { if(length != -1) {
py_newlistn(py_retval(), length); py_newlistn(py_retval(), length);
for(int i = 0; i < length; i++) { for(int i = 0; i < length; i++) {
py_list_setitem(py_retval(), i, p + i); py_list_setitem(py_retval(), i, p + i);

View File

@ -5,14 +5,13 @@
#include "pocketpy/interpreter/vm.h" #include "pocketpy/interpreter/vm.h"
#include "pocketpy/common/sstream.h" #include "pocketpy/common/sstream.h"
void pk_mappingproxy__namedict(py_Ref out, py_Ref object) {
void pk_mappingproxy__namedict(py_Ref out, py_Ref object){
py_newobject(out, tp_namedict, 1, 0); py_newobject(out, tp_namedict, 1, 0);
assert(object->is_ptr && object->_obj->slots == -1); assert(object->is_ptr && object->_obj->slots == -1);
py_setslot(out, 0, object); py_setslot(out, 0, object);
} }
static bool namedict__getitem__(int argc, py_Ref argv){ static bool namedict__getitem__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2); PY_CHECK_ARGC(2);
PY_CHECK_ARG_TYPE(1, tp_str); PY_CHECK_ARG_TYPE(1, tp_str);
py_Name name = py_namev(py_tosv(py_arg(1))); py_Name name = py_namev(py_tosv(py_arg(1)));
@ -22,7 +21,7 @@ static bool namedict__getitem__(int argc, py_Ref argv){
return true; return true;
} }
static bool namedict__setitem__(int argc, py_Ref argv){ static bool namedict__setitem__(int argc, py_Ref argv) {
PY_CHECK_ARGC(3); PY_CHECK_ARGC(3);
PY_CHECK_ARG_TYPE(1, tp_str); PY_CHECK_ARG_TYPE(1, tp_str);
py_Name name = py_namev(py_tosv(py_arg(1))); py_Name name = py_namev(py_tosv(py_arg(1)));
@ -31,7 +30,7 @@ static bool namedict__setitem__(int argc, py_Ref argv){
return true; return true;
} }
static bool namedict__delitem__(int argc, py_Ref argv){ static bool namedict__delitem__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2); PY_CHECK_ARGC(2);
PY_CHECK_ARG_TYPE(1, tp_str); PY_CHECK_ARG_TYPE(1, tp_str);
py_Name name = py_namev(py_tosv(py_arg(1))); py_Name name = py_namev(py_tosv(py_arg(1)));
@ -40,7 +39,7 @@ static bool namedict__delitem__(int argc, py_Ref argv){
return true; return true;
} }
static bool namedict__contains__(int argc, py_Ref argv){ static bool namedict__contains__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2); PY_CHECK_ARGC(2);
PY_CHECK_ARG_TYPE(1, tp_str); PY_CHECK_ARG_TYPE(1, tp_str);
py_Name name = py_namev(py_tosv(py_arg(1))); py_Name name = py_namev(py_tosv(py_arg(1)));
@ -49,6 +48,21 @@ static bool namedict__contains__(int argc, py_Ref argv){
return true; return true;
} }
static bool namedict_items(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
py_Ref object = py_getslot(argv, 0);
NameDict* dict = PyObject__dict(object->_obj);
py_newtuple(py_retval(), dict->count);
for(int i = 0; i < dict->count; i++) {
py_Ref slot = py_tuple_getitem(py_retval(), i);
py_newtuple(slot, 2);
NameDict_KV* kv = c11__at(NameDict_KV, dict, i);
py_newstr(py_tuple_getitem(slot, 0), py_name2str(kv->key));
py_assign(py_tuple_getitem(slot, 1), &kv->value);
}
return true;
}
py_Type pk_namedict__register() { py_Type pk_namedict__register() {
py_Type type = pk_newtype("namedict", tp_object, NULL, NULL, false, true); py_Type type = pk_newtype("namedict", tp_object, NULL, NULL, false, true);
@ -56,18 +70,20 @@ py_Type pk_namedict__register() {
py_bindmagic(type, __setitem__, namedict__setitem__); py_bindmagic(type, __setitem__, namedict__setitem__);
py_bindmagic(type, __delitem__, namedict__delitem__); py_bindmagic(type, __delitem__, namedict__delitem__);
py_bindmagic(type, __contains__, namedict__contains__); py_bindmagic(type, __contains__, namedict__contains__);
py_newnone(py_tpgetmagic(type, __hash__));
py_bindmethod(type, "items", namedict_items);
return type; return type;
} }
////////////////////// //////////////////////
void pk_mappingproxy__locals(py_Ref out, Frame* frame){ void pk_mappingproxy__locals(py_Ref out, Frame* frame) {
assert(frame->has_function && !frame->is_dynamic); assert(frame->has_function && !frame->is_dynamic);
Frame** ud = py_newobject(out, tp_locals, 0, sizeof(Frame*)); Frame** ud = py_newobject(out, tp_locals, 0, sizeof(Frame*));
*ud = frame; *ud = frame;
} }
static bool locals__getitem__(int argc, py_Ref argv){ static bool locals__getitem__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2); PY_CHECK_ARGC(2);
PY_CHECK_ARG_TYPE(1, tp_str); PY_CHECK_ARG_TYPE(1, tp_str);
Frame** ud = py_touserdata(argv); Frame** ud = py_touserdata(argv);
@ -78,7 +94,7 @@ static bool locals__getitem__(int argc, py_Ref argv){
return true; return true;
} }
static bool locals__setitem__(int argc, py_Ref argv){ static bool locals__setitem__(int argc, py_Ref argv) {
PY_CHECK_ARGC(3); PY_CHECK_ARGC(3);
PY_CHECK_ARG_TYPE(1, tp_str); PY_CHECK_ARG_TYPE(1, tp_str);
Frame** ud = py_touserdata(argv); Frame** ud = py_touserdata(argv);
@ -90,7 +106,7 @@ static bool locals__setitem__(int argc, py_Ref argv){
return true; return true;
} }
static bool locals__delitem__(int argc, py_Ref argv){ static bool locals__delitem__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2); PY_CHECK_ARGC(2);
PY_CHECK_ARG_TYPE(1, tp_str); PY_CHECK_ARG_TYPE(1, tp_str);
Frame** ud = py_touserdata(argv); Frame** ud = py_touserdata(argv);
@ -102,7 +118,7 @@ static bool locals__delitem__(int argc, py_Ref argv){
return true; return true;
} }
static bool locals__contains__(int argc, py_Ref argv){ static bool locals__contains__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2); PY_CHECK_ARGC(2);
PY_CHECK_ARG_TYPE(1, tp_str); PY_CHECK_ARG_TYPE(1, tp_str);
Frame** ud = py_touserdata(argv); Frame** ud = py_touserdata(argv);
@ -119,5 +135,6 @@ py_Type pk_locals__register() {
py_bindmagic(type, __setitem__, locals__setitem__); py_bindmagic(type, __setitem__, locals__setitem__);
py_bindmagic(type, __delitem__, locals__delitem__); py_bindmagic(type, __delitem__, locals__delitem__);
py_bindmagic(type, __contains__, locals__contains__); py_bindmagic(type, __contains__, locals__contains__);
py_newnone(py_tpgetmagic(type, __hash__));
return type; return type;
} }

View File

@ -4,8 +4,16 @@
#include <math.h> #include <math.h>
static bool try_castfloat(py_Ref self, double* out) {
switch(self->type) {
case tp_int: *out = (double)self->_i64; return true;
case tp_float: *out = self->_f64; return true;
default: return false;
}
}
#define DEF_NUM_BINARY_OP(name, op, rint, rfloat) \ #define DEF_NUM_BINARY_OP(name, op, rint, rfloat) \
static bool int##name(int argc, py_Ref argv) { \ static bool int##name(int argc, py_Ref argv) { \
PY_CHECK_ARGC(2); \ PY_CHECK_ARGC(2); \
if(py_isint(&argv[1])) { \ if(py_isint(&argv[1])) { \
py_i64 lhs = py_toint(&argv[0]); \ py_i64 lhs = py_toint(&argv[0]); \
@ -20,11 +28,11 @@
} \ } \
return true; \ return true; \
} \ } \
static bool float##name(int argc, py_Ref argv) { \ static bool float##name(int argc, py_Ref argv) { \
PY_CHECK_ARGC(2); \ PY_CHECK_ARGC(2); \
py_f64 lhs = py_tofloat(&argv[0]); \ py_f64 lhs = py_tofloat(&argv[0]); \
py_f64 rhs; \ py_f64 rhs; \
if(py_castfloat(&argv[1], &rhs)) { \ if(try_castfloat(&argv[1], &rhs)) { \
rfloat(py_retval(), lhs op rhs); \ rfloat(py_retval(), lhs op rhs); \
} else { \ } else { \
py_newnotimplemented(py_retval()); \ py_newnotimplemented(py_retval()); \
@ -63,7 +71,7 @@ static bool int__truediv__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2); PY_CHECK_ARGC(2);
py_i64 lhs = py_toint(&argv[0]); py_i64 lhs = py_toint(&argv[0]);
py_f64 rhs; py_f64 rhs;
if(py_castfloat(&argv[1], &rhs)) { if(try_castfloat(&argv[1], &rhs)) {
py_newfloat(py_retval(), lhs / rhs); py_newfloat(py_retval(), lhs / rhs);
} else { } else {
py_newnotimplemented(py_retval()); py_newnotimplemented(py_retval());
@ -75,7 +83,7 @@ static bool float__truediv__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2); PY_CHECK_ARGC(2);
py_f64 lhs = py_tofloat(&argv[0]); py_f64 lhs = py_tofloat(&argv[0]);
py_f64 rhs; py_f64 rhs;
if(py_castfloat(&argv[1], &rhs)) { if(try_castfloat(&argv[1], &rhs)) {
py_newfloat(py_retval(), lhs / rhs); py_newfloat(py_retval(), lhs / rhs);
} else { } else {
py_newnotimplemented(py_retval()); py_newnotimplemented(py_retval());
@ -107,8 +115,8 @@ static bool number__pow__(int argc, py_Ref argv) {
} }
} else { } else {
py_f64 lhs, rhs; py_f64 lhs, rhs;
py_castfloat(&argv[0], &lhs); if(!py_castfloat(&argv[0], &lhs)) return false;
if(py_castfloat(&argv[1], &rhs)) { if(try_castfloat(&argv[1], &rhs)) {
py_newfloat(py_retval(), pow(lhs, rhs)); py_newfloat(py_retval(), pow(lhs, rhs));
} else { } else {
py_newnotimplemented(py_retval()); py_newnotimplemented(py_retval());
@ -177,7 +185,7 @@ static bool int_bit_length(int argc, py_Ref argv) {
} }
#define DEF_INT_BITWISE_OP(name, op) \ #define DEF_INT_BITWISE_OP(name, op) \
static bool int##name(int argc, py_Ref argv) { \ static bool int##name(int argc, py_Ref argv) { \
PY_CHECK_ARGC(2); \ PY_CHECK_ARGC(2); \
py_i64 lhs = py_toint(&argv[0]); \ py_i64 lhs = py_toint(&argv[0]); \
if(py_isint(&argv[1])) { \ if(py_isint(&argv[1])) { \
@ -303,17 +311,16 @@ static bool int__new__(int argc, py_Ref argv) {
PY_CHECK_ARG_TYPE(1, tp_str); PY_CHECK_ARG_TYPE(1, tp_str);
int size; c11_sv sv = py_tosv(py_arg(1));
const char* data = py_tostrn(py_arg(1), &size);
bool negative = false; bool negative = false;
if(size && (data[0] == '+' || data[0] == '-')) { if(sv.size && (sv.data[0] == '+' || sv.data[0] == '-')) {
negative = data[0] == '-'; negative = sv.data[0] == '-';
data++; sv.data++;
size--; sv.size--;
} }
py_i64 val; py_i64 val;
if(c11__parse_uint((c11_sv){data, size}, &val, base) != IntParsing_SUCCESS) { if(c11__parse_uint(sv, &val, base) != IntParsing_SUCCESS) {
return ValueError("invalid literal for int() with base %d: %q", base, data); return ValueError("invalid literal for int() with base %d: %q", base, sv);
} }
py_newint(py_retval(), negative ? -val : val); py_newint(py_retval(), negative ? -val : val);
return true; return true;
@ -347,21 +354,20 @@ static bool float__new__(int argc, py_Ref argv) {
default: return TypeError("invalid arguments for float()"); default: return TypeError("invalid arguments for float()");
} }
// str to float // str to float
int size; c11_sv sv = py_tosv(py_arg(1));
const char* data = py_tostrn(py_arg(1), &size);
if(c11__streq(data, "inf")) { if(c11__sveq2(sv, "inf")) {
py_newfloat(py_retval(), INFINITY); py_newfloat(py_retval(), INFINITY);
return true; return true;
} }
if(c11__streq(data, "-inf")) { if(c11__sveq2(sv, "-inf")) {
py_newfloat(py_retval(), -INFINITY); py_newfloat(py_retval(), -INFINITY);
return true; return true;
} }
char* p_end; char* p_end;
py_f64 float_out = strtod(data, &p_end); py_f64 float_out = strtod(sv.data, &p_end);
if(p_end != data + size) { return ValueError("invalid literal for float(): %q", data); } if(p_end != sv.data + sv.size) return ValueError("invalid literal for float(): %q", sv);
py_newfloat(py_retval(), float_out); py_newfloat(py_retval(), float_out);
return true; return true;
} }
@ -369,11 +375,11 @@ static bool float__new__(int argc, py_Ref argv) {
// tp_bool // tp_bool
static bool bool__new__(int argc, py_Ref argv) { static bool bool__new__(int argc, py_Ref argv) {
assert(argc > 0); assert(argc > 0);
if(argc == 1){ if(argc == 1) {
py_newbool(py_retval(), false); py_newbool(py_retval(), false);
return true; return true;
} }
if(argc == 2){ if(argc == 2) {
int res = py_bool(py_arg(1)); int res = py_bool(py_arg(1));
if(res == -1) return false; if(res == -1) return false;
py_newbool(py_retval(), res); py_newbool(py_retval(), res);
@ -420,6 +426,25 @@ static bool bool__ne__(int argc, py_Ref argv) {
return true; return true;
} }
#define DEF_BOOL_BITWISE(name, op) \
static bool bool##name(int argc, py_Ref argv) { \
PY_CHECK_ARGC(2); \
bool lhs = py_tobool(&argv[0]); \
if(argv[1].type == tp_bool) { \
bool rhs = py_tobool(&argv[1]); \
py_newbool(py_retval(), lhs op rhs); \
} else { \
py_newnotimplemented(py_retval()); \
} \
return true; \
}
DEF_BOOL_BITWISE(__and__, &&)
DEF_BOOL_BITWISE(__or__, ||)
DEF_BOOL_BITWISE(__xor__, !=)
#undef DEF_BOOL_BITWISE
void pk_number__register() { void pk_number__register() {
/****** tp_int & tp_float ******/ /****** tp_int & tp_float ******/
py_bindmagic(tp_int, __add__, int__add__); py_bindmagic(tp_int, __add__, int__add__);
@ -493,4 +518,7 @@ void pk_number__register() {
py_bindmagic(tp_bool, __repr__, bool__repr__); py_bindmagic(tp_bool, __repr__, bool__repr__);
py_bindmagic(tp_bool, __eq__, bool__eq__); py_bindmagic(tp_bool, __eq__, bool__eq__);
py_bindmagic(tp_bool, __ne__, bool__ne__); py_bindmagic(tp_bool, __ne__, bool__ne__);
py_bindmagic(tp_bool, __and__, bool__and__);
py_bindmagic(tp_bool, __or__, bool__or__);
py_bindmagic(tp_bool, __xor__, bool__xor__);
} }

View File

@ -95,6 +95,19 @@ static bool type__getitem__(int argc, py_Ref argv) {
return true; return true;
} }
static bool type__module__getter(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
py_Type type = py_totype(argv);
py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, type);
if(py_isnil(&ti->module)) {
py_newnone(py_retval());
} else {
py_Ref path = py_getdict(&ti->module, __path__);
py_assign(py_retval(), path);
}
return true;
}
void pk_object__register() { void pk_object__register() {
// TODO: use staticmethod // TODO: use staticmethod
py_bindmagic(tp_object, __new__, object__new__); py_bindmagic(tp_object, __new__, object__new__);
@ -108,6 +121,7 @@ void pk_object__register() {
py_bindmagic(tp_type, __repr__, type__repr__); py_bindmagic(tp_type, __repr__, type__repr__);
py_bindmagic(tp_type, __new__, type__new__); py_bindmagic(tp_type, __new__, type__new__);
py_bindmagic(tp_type, __getitem__, type__getitem__); py_bindmagic(tp_type, __getitem__, type__getitem__);
py_bindproperty(tp_type, "__module__", type__module__getter, NULL);
py_bindproperty(tp_type, "__base__", type__base__getter, NULL); py_bindproperty(tp_type, "__base__", type__base__getter, NULL);
py_bindproperty(tp_type, "__name__", type__name__getter, NULL); py_bindproperty(tp_type, "__name__", type__name__getter, NULL);

View File

@ -50,7 +50,8 @@ bool py_hash(py_Ref val, int64_t* out) {
py_Ref _hash = &types[t].magic[__hash__]; py_Ref _hash = &types[t].magic[__hash__];
if(py_isnone(_hash)) break; if(py_isnone(_hash)) break;
py_Ref _eq = &types[t].magic[__eq__]; py_Ref _eq = &types[t].magic[__eq__];
if(!py_isnil(_hash) && !py_isnil(_eq)) { if(!py_isnil(_eq)) {
if(py_isnil(_hash)) break;
if(!py_call(_hash, 1, val)) return false; if(!py_call(_hash, 1, val)) return false;
if(!py_checkint(py_retval())) return false; if(!py_checkint(py_retval())) return false;
*out = py_toint(py_retval()); *out = py_toint(py_retval());

View File

@ -35,7 +35,7 @@ static bool range__new__(int argc, py_Ref argv) {
ud->stop = py_toint(py_arg(2)); ud->stop = py_toint(py_arg(2));
ud->step = py_toint(py_arg(3)); ud->step = py_toint(py_arg(3));
break; break;
default: return TypeError("range() expected at most 4 arguments, got %d", argc); default: return TypeError("range() expected at most 3 arguments, got %d", argc - 1);
} }
if(ud->step == 0) return ValueError("range() step must not be zero"); if(ud->step == 0) return ValueError("range() step must not be zero");
return true; return true;

View File

@ -262,32 +262,30 @@ static bool str_endswith(int argc, py_Ref argv) {
static bool str_join(int argc, py_Ref argv) { static bool str_join(int argc, py_Ref argv) {
PY_CHECK_ARGC(2); PY_CHECK_ARGC(2);
c11_sv self = c11_string__sv(py_touserdata(&argv[0])); c11_sv self = c11_string__sv(py_touserdata(argv));
py_Ref _1 = py_arg(1);
// join a list or tuple if(!py_iter(py_arg(1))) return false;
py_TValue* p; py_push(py_retval()); // iter
int length;
if(py_istype(_1, tp_list)) {
p = py_list_getitem(_1, 0);
length = py_list_len(_1);
} else if(py_istype(_1, tp_tuple)) {
p = py_tuple_getitem(_1, 0);
length = py_tuple_len(_1);
} else {
return TypeError("join() argument must be a list or tuple");
}
c11_sbuf buf; c11_sbuf buf;
c11_sbuf__ctor(&buf); c11_sbuf__ctor(&buf);
for(int i = 0; i < length; i++) { bool first = true;
if(i > 0) c11_sbuf__write_sv(&buf, self); while(true) {
if(!py_checkstr(&p[i])) { int res = py_next(py_peek(-1));
if(res == -1) return false;
if(res == 0) break;
if(!first) c11_sbuf__write_sv(&buf, self);
if(!py_checkstr(py_retval())) {
c11_sbuf__dtor(&buf); c11_sbuf__dtor(&buf);
return false; return false;
} }
c11_string* item = py_touserdata(&p[i]); c11_string* item = py_touserdata(py_retval());
c11_sbuf__write_cstrn(&buf, item->data, item->size); c11_sbuf__write_cstrn(&buf, item->data, item->size);
first = false;
} }
py_pop(); // iter
c11_sbuf__py_submit(&buf, py_retval()); c11_sbuf__py_submit(&buf, py_retval());
return true; return true;
} }
@ -516,17 +514,17 @@ py_Type pk_str_iterator__register() {
return type; return type;
} }
static bool bytes__new__(int argc, py_Ref argv){ static bool bytes__new__(int argc, py_Ref argv) {
if(argc == 1){ if(argc == 1) {
py_newbytes(py_retval(), 0); py_newbytes(py_retval(), 0);
return true; return true;
} }
if(argc > 2) return TypeError("bytes() takes at most 1 argument"); if(argc > 2) return TypeError("bytes() takes at most 1 argument");
int length; py_TValue* p;
py_TValue* p = pk_arrayview(&argv[1], &length); int length = pk_arrayview(&argv[1], &p);
if(!p) return TypeError("bytes() argument must be a list or tuple"); if(length == -1) return TypeError("bytes() argument must be a list or tuple");
unsigned char* data = py_newbytes(py_retval(), length); unsigned char* data = py_newbytes(py_retval(), length);
for(int i = 0; i < length; i++){ for(int i = 0; i < length; i++) {
if(!py_checktype(&p[i], tp_int)) return false; if(!py_checktype(&p[i], tp_int)) return false;
py_i64 v = py_toint(&p[i]); py_i64 v = py_toint(&p[i]);
if(v < 0 || v > 255) return ValueError("bytes must be in range(0, 256)"); if(v < 0 || v > 255) return ValueError("bytes must be in range(0, 256)");
@ -598,6 +596,17 @@ static bool bytes__ne__(int argc, py_Ref argv) {
return true; return true;
} }
static bool bytes__hash__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
c11_bytes* self = py_touserdata(&argv[0]);
uint64_t res = 0;
for(int i = 0; i < self->size; i++) {
res = res * 31 + self->data[i];
}
py_newint(py_retval(), res);
return true;
}
static bool bytes__add__(int argc, py_Ref argv) { static bool bytes__add__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2); PY_CHECK_ARGC(2);
c11_bytes* self = py_touserdata(&argv[0]); c11_bytes* self = py_touserdata(&argv[0]);
@ -630,6 +639,7 @@ py_Type pk_bytes__register() {
py_bindmagic(tp_bytes, __eq__, bytes__eq__); py_bindmagic(tp_bytes, __eq__, bytes__eq__);
py_bindmagic(tp_bytes, __ne__, bytes__ne__); py_bindmagic(tp_bytes, __ne__, bytes__ne__);
py_bindmagic(tp_bytes, __add__, bytes__add__); py_bindmagic(tp_bytes, __add__, bytes__add__);
py_bindmagic(tp_bytes, __hash__, bytes__hash__);
py_bindmethod(tp_bytes, "decode", bytes_decode); py_bindmethod(tp_bytes, "decode", bytes_decode);
return type; return type;

View File

@ -98,18 +98,7 @@ static bool tuple__getitem__(int argc, py_Ref argv) {
} }
static bool tuple__eq__(int argc, py_Ref argv) { static bool tuple__eq__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2); return pk_wrapper__arrayequal(tp_tuple, argc, argv);
if(py_istype(py_arg(1), tp_tuple)) {
int length0, length1;
py_TValue* a0 = pk_arrayview(py_arg(0), &length0);
py_TValue* a1 = pk_arrayview(py_arg(1), &length1);
int res = pk_arrayequal(a0, length0, a1, length1);
if(res == -1) return false;
py_newbool(py_retval(), res);
} else {
py_newnotimplemented(py_retval());
}
return true;
} }
static bool tuple__ne__(int argc, py_Ref argv) { static bool tuple__ne__(int argc, py_Ref argv) {

View File

@ -21,6 +21,9 @@ py_Ref py_getdict(py_Ref self, py_Name name) {
void py_setdict(py_Ref self, py_Name name, py_Ref val) { void py_setdict(py_Ref self, py_Name name, py_Ref val) {
assert(self && self->is_ptr); 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) { if(!py_ismagicname(name) || self->type != tp_type) {
NameDict__set(PyObject__dict(self->_obj), name, *val); NameDict__set(PyObject__dict(self->_obj), name, *val);
} else { } else {

View File

@ -10,7 +10,7 @@
#endif #endif
char* read_file(const char* path) { char* read_file(const char* path) {
FILE* file = fopen(path, "r"); FILE* file = fopen(path, "rb");
if(file == NULL) { if(file == NULL) {
printf("Error: file not found\n"); printf("Error: file not found\n");
return NULL; return NULL;
@ -19,7 +19,7 @@ char* read_file(const char* path) {
long size = ftell(file); long size = ftell(file);
fseek(file, 0, SEEK_SET); fseek(file, 0, SEEK_SET);
char* buffer = malloc(size + 1); char* buffer = malloc(size + 1);
fread(buffer, 1, size, file); size = fread(buffer, 1, size, file);
buffer[size] = 0; buffer[size] = 0;
return buffer; return buffer;
} }
@ -41,7 +41,11 @@ int main(int argc, char** argv) {
if(argc == 1) { if(argc == 1) {
printf("pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ") "); printf("pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ") ");
printf("[%d bit] on %s\n", (int)(sizeof(void*) * 8), PY_SYS_PLATFORM_STRING); printf("[%d bit] on %s", (int)(sizeof(void*) * 8), PY_SYS_PLATFORM_STRING);
#if PK_DEBUG
printf(" (DEBUG)");
#endif
printf("\n");
printf("https://github.com/pocketpy/pocketpy\n"); printf("https://github.com/pocketpy/pocketpy\n");
printf("Type \"exit()\" to exit.\n"); printf("Type \"exit()\" to exit.\n");

View File

@ -177,6 +177,10 @@ assert hex(17) == '0x11'
assert '-'.join(['r', 'u', 'n', 'o', 'o', 'b']) == 'r-u-n-o-o-b' assert '-'.join(['r', 'u', 'n', 'o', 'o', 'b']) == 'r-u-n-o-o-b'
assert (1 != '1') is True
assert (1 == '1') is False
assert 1 == 1.0
exit() exit()
# test format() # test format()

View File

@ -56,7 +56,7 @@ assert a == [1, 2, 3]
def f(): def f():
for i in range(5): for i in range(5):
yield str(i) yield str(i)
assert '|'.join(list(f())) == '0|1|2|3|4' assert '|'.join(f()) == '0|1|2|3|4'
def f(n): def f(n):

View File

@ -115,6 +115,8 @@ class ArithmeticError(Exception): pass
class BadCompare: class BadCompare:
def __eq__(self, other): def __eq__(self, other):
raise ArithmeticError raise ArithmeticError
def __ne__(self, other):
raise ArithmeticError
d = deque([1, 2, BadCompare(), 3]) d = deque([1, 2, BadCompare(), 3])

View File

@ -26,8 +26,10 @@ assert op.floordiv(1, 2) == 0
assert op.mod(1, 2) == 1 assert op.mod(1, 2) == 1
assert op.pow(2, 3) == 8 assert op.pow(2, 3) == 8
from linalg import mat3x3 class A:
assert op.matmul(mat3x3.identity(), mat3x3.identity()) == mat3x3.identity() def __matmul__(self, other):
return 'matmul'
assert op.matmul(A(), 1) == 'matmul'
a = [1, 2] a = [1, 2]
assert op.getitem(a, 0) == 1 assert op.getitem(a, 0) == 1

View File

@ -97,9 +97,9 @@ except:
# test hash: # test hash:
# 测试整数类型的输入 # 测试整数类型的输入
assert hash(0) == 0 assert type(hash(0)) is int
assert hash(123) == 123 assert type(hash(123)) is int
assert hash(-456) == -456 assert type(hash(-456)) is int
# 测试字符串类型的输入 # 测试字符串类型的输入
assert type(hash("hello")) is int assert type(hash("hello")) is int
@ -109,7 +109,7 @@ assert type(hash(3.14)) is int
assert type(hash(-2.71828)) is int assert type(hash(-2.71828)) is int
# 测试边界情况 # 测试边界情况
assert type(hash(None)) is int # assert type(hash(None)) is int
assert hash(True) == 1 assert hash(True) == 1
assert hash(False) == 0 assert hash(False) == 0
@ -154,7 +154,7 @@ assert len(actual) == len(expected)
for i in range(len(actual)): for i in range(len(actual)):
assert (actual[i] == expected[i]), (actual[i], expected[i]) assert (actual[i] == expected[i]), (actual[i], expected[i])
assert type(bin(1234)) is str # assert type(bin(1234)) is str
# test __repr__: # test __repr__:
class A(): class A():
@ -279,21 +279,21 @@ try:
except: except:
pass pass
assert (1,2,2,3,3,3).count(3) == 3 assert [1,2,2,3,3,3].count(3) == 3
assert (1,2,2,3,3,3).count(0) == 0 assert [1,2,2,3,3,3].count(0) == 0
assert 3 in (1, 3, 4) assert 3 in (1, 3, 4)
assert 5 not in (1, 3, 4) assert 5 not in (1, 3, 4)
assert repr(True) == 'True' assert repr(True) == 'True'
assert repr(False) == 'False' assert repr(False) == 'False'
assert True & True == 1 assert True & True == True
assert True | True == 1 assert True | False == True
assert (True ^ True) == 0 assert (True ^ True) == False
assert (True == True) == 1 assert (True == True) == True
assert type(hash(bytes([0x41, 0x42, 0x43]))) is int assert type(hash(bytes([0x41, 0x42, 0x43]))) is int
@ -328,40 +328,38 @@ assert s.step == 3
assert type(repr(slice(1,1,1))) is str assert type(repr(slice(1,1,1))) is str
# /************ namedict ************/ # /************ namedict ************/
# test namedict.keys: # # test namedict.keys:
class A(): # class A():
def __init__(self): # def __init__(self):
self.a = 10 # self.a = 10
def method(self): # def method(self):
pass # pass
my_namedict = A().__dict__ # my_namedict = A().__dict__
assert type(my_namedict.keys()) is list # assert type(my_namedict.keys()) is list
# # test namedict.values:
# class A():
# def __init__(self):
# self.a = 10
# def method(self):
# pass
# 未完全测试准确性----------------------------------------------- # my_namedict = A().__dict__
# test namedict.values: # assert type(my_namedict.values()) is list
class A():
def __init__(self):
self.a = 10
def method(self):
pass
my_namedict = A().__dict__ # class A():
assert type(my_namedict.values()) is list # def __init__(self):
# self.a = 10
# def method(self):
# pass
class A(): # my_namedict = A().__dict__
def __init__(self): # assert type(len(my_namedict)) is int
self.a = 10
def method(self):
pass
my_namedict = A().__dict__
assert type(len(my_namedict)) is int
class A(): class A():
@ -432,7 +430,7 @@ except:
pass pass
# test dict.__iter__ # test dict.__iter__
for k in {1:2, 2:3, 3:4}: for k in {1:2, 2:3, 3:4}.keys():
assert k in [1,2,3] assert k in [1,2,3]
# 未完全测试准确性----------------------------------------------- # 未完全测试准确性-----------------------------------------------

View File

@ -1,50 +0,0 @@
assert long(123) == long('123') == 123 == 123L
a = long(2)
assert a ** 0 == 1
assert a ** 60 == 1152921504606846976
assert a + 1 == 3
assert a - 1 == 1
assert a * 2 == 4
assert a // 2 == 1
assert -a == -2
assert 1 + a == 3L
assert 1 - a == -1L
assert 2 * a == 4L
# __lshift__ and __rshift__
for i in range(29):
assert 1L << i == 2 ** i
for i in range(29):
assert 2L ** i >> i == 1L
assert 12L >> 100 == 0
a = 32764L
s = []
while a != 0:
a, r = divmod(a, 10L)
s.append(r)
assert s == [4, 6, 7, 2, 3]
assert 1 < 2L < 3 < 6.6
assert 1L < 2 < 9.6 >= 7 > 2L
assert 1L < 2 < 3 < 6.6
assert 10000000000000000000000L // 3333L == 3000300030003000300L
assert 10000000000000000000000L % 3333L == 100L
assert 2L ** 100 // 3L ** 50 == 1765780L
assert 2L ** 200 // 3L ** 100 == 3117982410207L
assert 2L ** 500 // 3L ** 200 == 12323863745843010927046405923587284941366070573310012484L
assert 2L ** 500 % 3L ** 200 == 242990057207501525999897657892105676264485903550870122812212566096970021710762636168532352280892L
assert 3L**500 // 3L**400 == 3L**100
assert 4562645248L // 3L == 1520881749L
assert 3L**10 // 2L**200 == 0
assert 2L**500 % 3L**200 == 242990057207501525999897657892105676264485903550870122812212566096970021710762636168532352280892L
assert divmod(10L**115, 3L**47) == (376098003656605353510839433041026531338835641081336270795298342081499446459650747504311257564L, 10150482013473427429132L)