mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-19 19:10:17 +00:00
...
This commit is contained in:
parent
76075de70c
commit
88f893ddd7
2
build.sh
2
build.sh
@ -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..."
|
||||||
|
@ -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[];
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
352
python/_long.py
352
python/_long.py
@ -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'
|
|
@ -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):
|
||||||
|
@ -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})"
|
||||||
|
|
||||||
|
@ -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):
|
||||||
|
File diff suppressed because one or more lines are too long
@ -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 },
|
||||||
|
@ -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);
|
||||||
|
@ -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++) {
|
||||||
|
@ -571,7 +571,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 +590,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 +663,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,
|
||||||
|
@ -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) {
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
@ -144,11 +144,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 +273,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;
|
||||||
@ -394,6 +394,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 +522,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;
|
||||||
@ -552,6 +571,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,6 +579,8 @@ 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_bindmagic(tp_ellipsis, __repr__, ellipsis__repr__);
|
py_bindmagic(tp_ellipsis, __repr__, ellipsis__repr__);
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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,19 @@ 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_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 +93,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 +105,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 +117,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);
|
||||||
|
@ -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])) { \
|
||||||
@ -369,11 +377,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);
|
||||||
|
@ -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);
|
||||||
|
@ -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)");
|
||||||
|
@ -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) {
|
||||||
|
7
tests/00_tmp.py
Normal file
7
tests/00_tmp.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from cmath import isclose, sqrt
|
||||||
|
|
||||||
|
res = sqrt(1+2j)
|
||||||
|
assert isclose(res, 1.272019649514069+0.7861513777574233j)
|
||||||
|
|
||||||
|
a = 1+2j
|
||||||
|
{a: 1}
|
@ -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()
|
||||||
|
@ -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):
|
||||||
|
@ -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])
|
@ -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)
|
|
Loading…
x
Reference in New Issue
Block a user