This commit is contained in:
blueloveTH 2024-08-10 20:21:40 +08:00
parent 76075de70c
commit 88f893ddd7
36 changed files with 437 additions and 693 deletions

View File

@ -33,7 +33,7 @@ else
LINK_FLAGS="-Wl,-rpath=."
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
echo "> Compiling main.c and linking to libpocketpy$LIB_EXTENSION..."

View File

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

View File

@ -10,7 +10,7 @@ extern const char* TokenSymbols[];
typedef enum TokenIndex{
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_IS_NOT, TK_NOT_IN, TK_YIELD_FROM,

View File

@ -6,6 +6,11 @@
#include "pocketpy/interpreter/frame.h"
#include "pocketpy/interpreter/modules.h"
// TODO:
// 1. __eq__ and __ne__ fallbacks
// 2. un-cleared exception detection
// 3. super()
typedef struct py_TypeInfo {
py_Name name;
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);
py_TValue* pk_arrayview(py_Ref self, int* length);
int pk_arrayequal(py_TValue* lhs, int lhs_length, py_TValue* rhs, int rhs_length);
int pk_arrayview(py_Ref self, py_TValue** p);
bool pk_wrapper__arrayequal(py_Type type, int argc, py_Ref argv);
bool pk_arrayiter(py_Ref val);
bool pk_arraycontains(py_Ref self, py_Ref val);

View File

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

View File

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

View File

@ -174,13 +174,10 @@ def help(obj):
if obj.__doc__:
print(obj.__doc__)
def complex(*args, **kwargs):
def complex(real, imag=0):
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:
def __init__(self, iterable=None):

View File

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

View File

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

File diff suppressed because one or more lines are too long

View File

@ -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);
bool ok = py_compile(source->data, "<f-string>", EVAL_MODE, false);
if(!ok){
bool ok = py_compile(source->data, "<f-string>", EVAL_MODE, true);
if(!ok) {
py_printexc();
c11__abort("f-string: invalid expression");
}
@ -1662,12 +1662,6 @@ static Error* exprLiteral(Compiler* self) {
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) {
c11_sv sv = c11_string__sv(prev()->value._str);
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_STR] = { exprLiteral, },
[TK_FSTR] = { exprFString, },
[TK_LONG] = { exprLong, },
[TK_IMAG] = { exprImag, },
[TK_BYTES] = { exprBytes, },
[TK_LBRACE] = { exprMap },

View File

@ -8,17 +8,17 @@
#include <stdarg.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;
const char* token_start;
const char* curr_char;
int current_line;
int brackets_level;
c11_vector/*T=Token*/ nexts;
c11_vector/*T=int*/ indents;
c11_vector /*T=Token*/ nexts;
c11_vector /*T=int*/ indents;
} Lexer;
typedef struct TokenDeserializer {
@ -34,10 +34,9 @@ int TokenDeserializer__read_count(TokenDeserializer* self);
int64_t TokenDeserializer__read_uint(TokenDeserializer* self, char c);
double TokenDeserializer__read_float(TokenDeserializer* self, char c);
const static TokenValue EmptyTokenValue;
static void Lexer__ctor(Lexer* self, SourceData_ src){
static void Lexer__ctor(Lexer* self, SourceData_ src) {
PK_INCREF(src);
self->src = src;
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));
}
static void Lexer__dtor(Lexer* self){
static void Lexer__dtor(Lexer* self) {
PK_DECREF(self->src);
c11_vector__dtor(&self->nexts);
c11_vector__dtor(&self->indents);
}
static char eatchar(Lexer* self){
static char eatchar(Lexer* self) {
char c = *self->curr_char;
assert(c != '\n'); // eatchar() cannot consume a newline
self->curr_char++;
return c;
}
static char eatchar_include_newline(Lexer* self){
static char eatchar_include_newline(Lexer* self) {
char c = *self->curr_char;
self->curr_char++;
if(c == '\n') {
@ -70,7 +69,7 @@ static char eatchar_include_newline(Lexer* self){
return c;
}
static int eat_spaces(Lexer* self){
static int eat_spaces(Lexer* self) {
int count = 0;
while(true) {
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;
eatchar_include_newline(self);
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;
for(int i = 0; i < n; i++) {
if(*c == '\0') return false;
@ -100,14 +99,14 @@ static bool match_n_chars(Lexer* self, int n, char c0){
return true;
}
static void skip_line_comment(Lexer* self){
static void skip_line_comment(Lexer* self) {
while(*self->curr_char) {
if(*self->curr_char == '\n') return;
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) {
case TK_LBRACE:
case TK_LBRACKET:
@ -118,11 +117,11 @@ static void add_token_with_value(Lexer* self, TokenIndex type, TokenValue value)
default: break;
}
Token token = {type,
self->token_start,
(int)(self->curr_char - self->token_start),
self->current_line - ((type == TK_EOL) ? 1 : 0),
self->brackets_level,
value};
self->token_start,
(int)(self->curr_char - self->token_start),
self->current_line - ((type == TK_EOL) ? 1 : 0),
self->brackets_level,
value};
// handle "not in", "is not", "yield from"
if(self->nexts.count > 0) {
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);
}
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))
add_token(self, two);
else
add_token(self, one);
}
static bool eat_indentation(Lexer* self){
static bool eat_indentation(Lexer* self) {
if(self->brackets_level > 0) return true;
int spaces = eat_spaces(self);
if(*self->curr_char == '#') skip_line_comment(self);
if(*self->curr_char == '\0' || *self->curr_char == '\n'){
return true;
}
if(*self->curr_char == '\0' || *self->curr_char == '\n') { return true; }
// https://docs.python.org/3/reference/lexical_analysis.html#indentation
int indents_back = c11_vector__back(int, &self->indents);
if(spaces > indents_back) {
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);
} else if(spaces < indents_back) {
do {
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);
indents_back = c11_vector__back(int, &self->indents);
} while(spaces < indents_back);
@ -178,28 +185,26 @@ static bool eat_indentation(Lexer* self){
return true;
}
static bool is_possible_number_char(char c){
static bool is_possible_number_char(char c) {
switch(c) {
// clang-format off
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 '.': case 'L': case 'x': case 'o': case 'j':
case '.': case 'x': case 'o': case 'j':
return true;
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));
err->src = self->src;
PK_INCREF(self->src);
err->lineno = self->current_line;
if(*self->curr_char == '\n') {
err->lineno--;
}
if(*self->curr_char == '\n') { err->lineno--; }
va_list args;
va_start(args, fmt);
vsnprintf(err->msg, sizeof(err->msg), fmt, args);
@ -207,7 +212,7 @@ static Error* SyntaxError(Lexer* self, const char* fmt, ...){
return err;
}
static Error* eat_name(Lexer* self){
static Error* eat_name(Lexer* self) {
self->curr_char--;
while(true) {
unsigned char c = *self->curr_char;
@ -236,9 +241,9 @@ static Error* eat_name(Lexer* self){
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;
}else{
} else {
break;
}
}
@ -249,10 +254,10 @@ static Error* eat_name(Lexer* self){
const char** KW_BEGIN = TokenSymbols + 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;
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])) {
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;
}
if(c == '\0') {
return SyntaxError(self, "EOL while scanning string literal");
}
if(c == '\0') { return SyntaxError(self, "EOL while scanning string literal"); }
if(c == '\n') {
if(!quote3)
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;
}
enum StringType {
NORMAL_STRING,
RAW_STRING,
F_STRING,
NORMAL_BYTES
};
enum StringType { 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;
Error* err = eat_string_until(self, quote, type == RAW_STRING, &s);
if(err) return err;
TokenValue value = {TokenValue_STR, ._str = s};
if(type == F_STRING) {
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);
}else{
} else {
add_token_with_value(self, TK_STR, value);
}
return NULL;
}
static Error* eat_number(Lexer* self){
static Error* eat_number(Lexer* self) {
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;
if(*(i - 1) == 'e' && (*i == '+' || *i == '-')) {
i++;
while(isdigit(*i) || *i == 'j') i++;
while(isdigit(*i) || *i == 'j')
i++;
is_scientific_notation = true;
}
@ -351,21 +351,12 @@ static Error* eat_number(Lexer* self){
self->curr_char = i;
if(text.data[0] != '.' && !is_scientific_notation) {
// try long
if(i[-1] == 'L') {
add_token(self, TK_LONG);
return NULL;
}
// try integer
TokenValue value = {.index = TokenValue_I64};
switch(c11__parse_uint(text, &value._i64, -1)) {
case IntParsing_SUCCESS:
add_token_with_value(self, TK_NUM, value);
return NULL;
case IntParsing_OVERFLOW:
return SyntaxError(self, "int literal is too large");
case IntParsing_FAILURE:
break; // do nothing
case IntParsing_SUCCESS: add_token_with_value(self, TK_NUM, value); return NULL;
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;
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};
add_token_with_value(self, TK_NUM, value);
return NULL;
@ -389,7 +380,7 @@ static Error* eat_number(Lexer* self){
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;
while(*self->curr_char) {
self->token_start = self->curr_char;
@ -474,9 +465,9 @@ static Error* lex_one_token(Lexer* self, bool* eof){
return NULL;
}
case '!':
if(matchchar(self, '=')){
if(matchchar(self, '=')) {
add_token(self, TK_NE);
}else{
} else {
Error* err = SyntaxError(self, "expected '=' after '!'");
if(err) return err;
}
@ -499,7 +490,7 @@ static Error* lex_one_token(Lexer* self, bool* eof){
case '\t': eat_spaces(self); break;
case '\n': {
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 NULL;
@ -542,7 +533,7 @@ static Error* from_precompiled(Lexer* self) {
if(c11_sv__cmp2(version, PK_VERSION) != 0) {
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");
}
@ -580,7 +571,7 @@ static Error* from_precompiled(Lexer* self) {
t.brackets_level = (int)TokenDeserializer__read_uint(&deserializer, ',');
}
char type = (*deserializer.curr++); // read_char
char type = (*deserializer.curr++); // read_char
switch(type) {
case 'I': {
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');
t.value = (TokenValue){TokenValue_STR, ._str = res};
} break;
default:
t.value = EmptyTokenValue;
break;
default: t.value = EmptyTokenValue; break;
}
c11_vector__push(Token, &self->nexts, t);
}
return NULL;
}
Error* Lexer__process(SourceData_ src, TokenArray* out_tokens){
Error* Lexer__process(SourceData_ src, TokenArray* out_tokens) {
Lexer lexer;
Lexer__ctor(&lexer, src);
@ -614,14 +603,15 @@ Error* Lexer__process(SourceData_ src, TokenArray* out_tokens){
return err;
}
// 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(int, &lexer.indents, 0);
bool eof = false;
while(!eof) {
void* err = lex_one_token(&lexer, &eof);
if(err){
if(err) {
Lexer__dtor(&lexer);
return err;
}
@ -635,7 +625,7 @@ Error* Lexer__process(SourceData_ src, TokenArray* out_tokens){
Error* Lexer__process_and_dump(SourceData_ src, c11_string** out) {
assert(!src->is_precompiled);
TokenArray nexts; // output tokens
TokenArray nexts; // output tokens
Error* err = Lexer__process(src, &nexts);
if(err) return err;
@ -665,7 +655,7 @@ Error* Lexer__process_and_dump(SourceData_ src, c11_string** out) {
c11_sbuf__write_char(&ss, '\n');
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);
// L4: raw strings
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, ',');
if(is_raw_string_used(token->type)) {
uint16_t *p = c11_smallmap_s2n__try_get(
&token_indices, (c11_sv){token->start, token->length});
uint16_t* p =
c11_smallmap_s2n__try_get(&token_indices, (c11_sv){token->start, token->length});
assert(p != NULL);
c11_sbuf__write_int(&ss, (int)*p);
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, ',');
}else{
} else {
c11_sbuf__write_int(&ss, token->line);
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, ',');
}else{
} else {
c11_sbuf__write_int(&ss, token->brackets_level);
c11_sbuf__write_char(&ss, ',');
}
// visit token value
switch(token->value.index){
switch(token->value.index) {
case TokenValue_EMPTY: break;
case TokenValue_I64:
c11_sbuf__write_char(&ss, 'I');
@ -716,7 +706,7 @@ Error* Lexer__process_and_dump(SourceData_ src, c11_string** out) {
case TokenValue_STR: {
c11_sbuf__write_char(&ss, 'S');
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);
}
break;
@ -729,46 +719,120 @@ Error* Lexer__process_and_dump(SourceData_ src, c11_string** out) {
return NULL;
}
void TokenArray__dtor(TokenArray *self){
void TokenArray__dtor(TokenArray* self) {
Token* data = self->data;
for(int i=0; i<self->count; i++){
if(data[i].value.index == TokenValue_STR){
c11_string__delete(data[i].value._str);
}
for(int i = 0; i < self->count; i++) {
if(data[i].value.index == TokenValue_STR) { c11_string__delete(data[i].value._str); }
}
c11_array__dtor(self);
}
const char* TokenSymbols[] = {
"@eof", "@eol", "@sof",
"@id", "@num", "@str", "@fstr", "@long", "@bytes", "@imag",
"@indent", "@dedent",
"@eof",
"@eol",
"@sof",
"@id",
"@num",
"@str",
"@fstr",
"@bytes",
"@imag",
"@indent",
"@dedent",
// 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 **/
// NOTE: These keywords should be sorted in ascending order!!
"False", "None", "True", "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",
"False",
"None",
"True",
"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->source = source;
}
bool TokenDeserializer__match_char(TokenDeserializer* self, char c){
bool TokenDeserializer__match_char(TokenDeserializer* self, char c) {
if(*self->curr == c) {
self->curr++;
return true;
@ -776,16 +840,16 @@ bool TokenDeserializer__match_char(TokenDeserializer* self, char c){
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;
while(*self->curr != c)
self->curr++;
c11_sv retval = {start, (int)(self->curr-start)};
c11_sv retval = {start, (int)(self->curr - start)};
self->curr++; // skip the delimiter
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);
const char* s = sv.data;
c11_sbuf ss;
@ -810,13 +874,13 @@ c11_string* TokenDeserializer__read_string_from_hex(TokenDeserializer* self, cha
return c11_sbuf__submit(&ss);
}
int TokenDeserializer__read_count(TokenDeserializer* self){
int TokenDeserializer__read_count(TokenDeserializer* self) {
assert(*self->curr == '=');
self->curr++;
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;
while(*self->curr != c) {
out = out * 10 + (*self->curr - '0');
@ -826,7 +890,7 @@ int64_t TokenDeserializer__read_uint(TokenDeserializer* self, char c){
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);
// TODO: optimize this
c11_string* nullterm = c11_string__new2(sv.data, sv.size);

View File

@ -89,6 +89,13 @@ FrameResult VM__run_top_frame(VM* self) {
pk_print_stack(self, frame, byte);
// #if PK_DEBUG
// if(py_checkexc()) {
// py_printexc();
// c11__abort("unhandled exception!");
// }
// #endif
switch((Opcode)byte.op) {
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);
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: {
// [x]
py_Ref f = py_getdict(&self->builtins, py_name("complex"));
@ -694,9 +691,9 @@ FrameResult VM__run_top_frame(VM* self) {
buf[n++] = *curr;
} else {
py_TValue* args = py_getslot(curr, 0);
int length;
py_TValue* p = pk_arrayview(args, &length);
if(p) {
py_TValue* p;
int length = pk_arrayview(args, &p);
if(length != -1) {
for(int j = 0; j < length; j++) {
buf[n++] = p[j];
}
@ -827,7 +824,7 @@ FrameResult VM__run_top_frame(VM* self) {
int res = py_import(path);
if(res == -1) goto __ERROR;
if(res == 0) {
ImportError("module '%s' not found", path);
ImportError("No module named '%s'", path);
goto __ERROR;
}
PUSH(py_retval());
@ -838,9 +835,9 @@ FrameResult VM__run_top_frame(VM* self) {
NameDict* dict = PyObject__dict(TOP()->_obj);
py_Ref all = NameDict__try_get(dict, __all__);
if(all) {
int length;
py_TValue* p = pk_arrayview(all, &length);
if(!p) {
py_TValue* p;
int length = pk_arrayview(all, &p);
if(length == -1) {
TypeError("'__all__' must be a list or tuple, got '%t'", all->type);
goto __ERROR;
}
@ -872,10 +869,10 @@ FrameResult VM__run_top_frame(VM* self) {
DISPATCH();
}
case OP_UNPACK_EX: {
int length;
py_TValue* p = pk_arrayview(TOP(), &length);
if(!p) {
TypeError("expected list or tuple to unpack, got '%t'", TOP()->type);
py_TValue* p;
int length = pk_arrayview(TOP(), &p);
if(length == -1) {
TypeError("expected list or tuple to unpack, got %t", TOP()->type);
goto __ERROR;
}
int exceed = length - byte.arg;
@ -1027,9 +1024,12 @@ FrameResult VM__run_top_frame(VM* self) {
}
//////////////////
case OP_FSTRING_EVAL: {
py_TValue* tmp = c11__at(py_TValue, &frame->co->consts, byte.arg);
assert(py_istype(tmp, tp_code));
if(!pk_exec(py_touserdata(tmp), frame->module)) goto __ERROR;
py_TValue* code = c11__at(py_TValue, &frame->co->consts, byte.arg);
assert(py_istype(code, tp_code));
py_newglobals(SP()++);
py_newlocals(SP()++);
PUSH(code);
if(!pk_exec(py_touserdata(code), frame->module)) goto __ERROR;
PUSH(py_retval());
DISPATCH();
}
@ -1100,11 +1100,15 @@ bool pk_stack_binaryop(VM* self, py_Name op, py_Name rop) {
}
}
// 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);
return true;
}
if(op == __ne__) {
py_newbool(py_retval(), !res);
return true;
}
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) {
int length;
py_TValue* p = pk_arrayview(TOP(), &length);
if(!p) return TypeError("expected list or tuple to unpack, got '%t'", TOP()->type);
py_TValue* p;
int length = pk_arrayview(TOP(), &p);
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);
POP();
for(int i = 0; i < length; i++) {

View File

@ -571,7 +571,7 @@ static void mark_object(PyObject* obj) {
}
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) {
@ -590,6 +590,17 @@ void ManagedHeap__mark(ManagedHeap* self) {
for(py_TValue* p = vm->stack.begin; p != vm->stack.end; 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
for(Frame* frame = vm->top_frame; frame; frame = frame->f_back) {
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);
printf("L%-3d: %-25s %-6d [%s]\n",
printf("%s:%-3d: %-25s %-6d [%s]\n",
frame->co->src->filename->data,
Frame__lineno(frame),
pk_opname(byte.op),
byte.arg,

View File

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

View File

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

View File

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

View File

@ -144,11 +144,11 @@ int py_import(const char* path_cstr) {
return 0;
__SUCCESS:
py_push(py_newmodule(path_cstr));
py_Ref mod = py_peek(-1);
do {
} while(0);
py_GlobalRef mod = py_newmodule(path_cstr);
bool ok = py_exec((const char*)data, filename->data, EXEC_MODE, mod);
py_assign(py_retval(), mod);
py_pop();
c11_string__delete(filename);
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) {
int length;
py_TValue* args = pk_arrayview(argv, &length);
assert(args != NULL);
py_TValue* args;
int length = pk_arrayview(argv, &args);
assert(length != -1);
c11_sv sep = py_tosv(py_arg(1));
c11_sv end = py_tosv(py_arg(2));
c11_sbuf buf;
@ -394,6 +394,16 @@ static bool builtins_ord(int argc, py_Ref argv) {
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) {
PY_CHECK_ARGC(0);
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);
}
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) {
py_newstr(py_retval(), "None");
return true;
@ -552,6 +571,7 @@ py_TValue pk_builtins__register() {
py_bindfunc(builtins, "chr", builtins_chr);
py_bindfunc(builtins, "ord", builtins_ord);
py_bindfunc(builtins, "id", builtins_id);
py_bindfunc(builtins, "globals", builtins_globals);
py_bindfunc(builtins, "locals", builtins_locals);
@ -559,6 +579,8 @@ py_TValue pk_builtins__register() {
py_bindfunc(builtins, "eval", builtins_eval);
py_bindfunc(builtins, "compile", builtins_compile);
py_bindfunc(builtins, "__import__", builtins__import__);
// some patches
py_bindmagic(tp_NoneType, __repr__, NoneType__repr__);
py_bindmagic(tp_ellipsis, __repr__, ellipsis__repr__);

View File

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

View File

@ -206,10 +206,18 @@ static DictEntry* DictIterator__next(DictIterator* self) {
///////////////////////////////
static bool dict__new__(int argc, py_Ref argv) {
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;
}
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) {
py_newnone(py_retval());
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;
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));
}
@ -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) {
assert(py_isdict(self));
Dict* ud = py_touserdata(self);

View File

@ -75,18 +75,7 @@ static bool list__len__(int argc, py_Ref argv) {
}
static bool list__eq__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
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;
return pk_wrapper__arrayequal(tp_list, argc, 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;
}
if(argc == 2) {
int length;
py_TValue* p = pk_arrayview(py_arg(1), &length);
if(p) {
py_TValue* p;
int length = pk_arrayview(py_arg(1), &p);
if(length != -1) {
py_newlistn(py_retval(), length);
for(int i = 0; i < length; i++) {
py_list_setitem(py_retval(), i, p + i);

View File

@ -5,14 +5,13 @@
#include "pocketpy/interpreter/vm.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);
assert(object->is_ptr && object->_obj->slots == -1);
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_ARG_TYPE(1, tp_str);
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;
}
static bool namedict__setitem__(int argc, py_Ref argv){
static bool namedict__setitem__(int argc, py_Ref argv) {
PY_CHECK_ARGC(3);
PY_CHECK_ARG_TYPE(1, tp_str);
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;
}
static bool namedict__delitem__(int argc, py_Ref argv){
static bool namedict__delitem__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
PY_CHECK_ARG_TYPE(1, tp_str);
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;
}
static bool namedict__contains__(int argc, py_Ref argv){
static bool namedict__contains__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
PY_CHECK_ARG_TYPE(1, tp_str);
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;
}
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 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, __delitem__, namedict__delitem__);
py_bindmagic(type, __contains__, namedict__contains__);
py_bindmethod(type, "items", namedict_items);
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);
Frame** ud = py_newobject(out, tp_locals, 0, sizeof(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_ARG_TYPE(1, tp_str);
Frame** ud = py_touserdata(argv);
@ -78,7 +93,7 @@ static bool locals__getitem__(int argc, py_Ref argv){
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_ARG_TYPE(1, tp_str);
Frame** ud = py_touserdata(argv);
@ -90,7 +105,7 @@ static bool locals__setitem__(int argc, py_Ref argv){
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_ARG_TYPE(1, tp_str);
Frame** ud = py_touserdata(argv);
@ -102,7 +117,7 @@ static bool locals__delitem__(int argc, py_Ref argv){
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_ARG_TYPE(1, tp_str);
Frame** ud = py_touserdata(argv);

View File

@ -4,8 +4,16 @@
#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) \
static bool int##name(int argc, py_Ref argv) { \
static bool int##name(int argc, py_Ref argv) { \
PY_CHECK_ARGC(2); \
if(py_isint(&argv[1])) { \
py_i64 lhs = py_toint(&argv[0]); \
@ -20,11 +28,11 @@
} \
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_f64 lhs = py_tofloat(&argv[0]); \
py_f64 rhs; \
if(py_castfloat(&argv[1], &rhs)) { \
if(try_castfloat(&argv[1], &rhs)) { \
rfloat(py_retval(), lhs op rhs); \
} else { \
py_newnotimplemented(py_retval()); \
@ -63,7 +71,7 @@ static bool int__truediv__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
py_i64 lhs = py_toint(&argv[0]);
py_f64 rhs;
if(py_castfloat(&argv[1], &rhs)) {
if(try_castfloat(&argv[1], &rhs)) {
py_newfloat(py_retval(), lhs / rhs);
} else {
py_newnotimplemented(py_retval());
@ -75,7 +83,7 @@ static bool float__truediv__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
py_f64 lhs = py_tofloat(&argv[0]);
py_f64 rhs;
if(py_castfloat(&argv[1], &rhs)) {
if(try_castfloat(&argv[1], &rhs)) {
py_newfloat(py_retval(), lhs / rhs);
} else {
py_newnotimplemented(py_retval());
@ -107,8 +115,8 @@ static bool number__pow__(int argc, py_Ref argv) {
}
} else {
py_f64 lhs, rhs;
py_castfloat(&argv[0], &lhs);
if(py_castfloat(&argv[1], &rhs)) {
if(!py_castfloat(&argv[0], &lhs)) return false;
if(try_castfloat(&argv[1], &rhs)) {
py_newfloat(py_retval(), pow(lhs, rhs));
} else {
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) \
static bool int##name(int argc, py_Ref argv) { \
static bool int##name(int argc, py_Ref argv) { \
PY_CHECK_ARGC(2); \
py_i64 lhs = py_toint(&argv[0]); \
if(py_isint(&argv[1])) { \
@ -369,11 +377,11 @@ static bool float__new__(int argc, py_Ref argv) {
// tp_bool
static bool bool__new__(int argc, py_Ref argv) {
assert(argc > 0);
if(argc == 1){
if(argc == 1) {
py_newbool(py_retval(), false);
return true;
}
if(argc == 2){
if(argc == 2) {
int res = py_bool(py_arg(1));
if(res == -1) return false;
py_newbool(py_retval(), res);

View File

@ -95,6 +95,19 @@ static bool type__getitem__(int argc, py_Ref argv) {
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() {
// TODO: use staticmethod
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, __new__, type__new__);
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, "__name__", type__name__getter, NULL);

View File

@ -262,32 +262,30 @@ static bool str_endswith(int argc, py_Ref argv) {
static bool str_join(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
c11_sv self = c11_string__sv(py_touserdata(&argv[0]));
py_Ref _1 = py_arg(1);
// join a list or tuple
py_TValue* p;
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_sv self = c11_string__sv(py_touserdata(argv));
if(!py_iter(py_arg(1))) return false;
py_push(py_retval()); // iter
c11_sbuf buf;
c11_sbuf__ctor(&buf);
for(int i = 0; i < length; i++) {
if(i > 0) c11_sbuf__write_sv(&buf, self);
if(!py_checkstr(&p[i])) {
bool first = true;
while(true) {
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);
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);
first = false;
}
py_pop(); // iter
c11_sbuf__py_submit(&buf, py_retval());
return true;
}
@ -516,17 +514,17 @@ py_Type pk_str_iterator__register() {
return type;
}
static bool bytes__new__(int argc, py_Ref argv){
if(argc == 1){
static bool bytes__new__(int argc, py_Ref argv) {
if(argc == 1) {
py_newbytes(py_retval(), 0);
return true;
}
if(argc > 2) return TypeError("bytes() takes at most 1 argument");
int length;
py_TValue* p = pk_arrayview(&argv[1], &length);
if(!p) return TypeError("bytes() argument must be a list or tuple");
py_TValue* p;
int length = pk_arrayview(&argv[1], &p);
if(length == -1) return TypeError("bytes() argument must be a list or tuple");
unsigned char* data = py_newbytes(py_retval(), length);
for(int i = 0; i < length; i++){
for(int i = 0; i < length; i++) {
if(!py_checktype(&p[i], tp_int)) return false;
py_i64 v = py_toint(&p[i]);
if(v < 0 || v > 255) return ValueError("bytes must be in range(0, 256)");

View File

@ -98,18 +98,7 @@ static bool tuple__getitem__(int argc, py_Ref argv) {
}
static bool tuple__eq__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
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;
return pk_wrapper__arrayequal(tp_tuple, argc, argv);
}
static bool tuple__ne__(int argc, py_Ref argv) {

7
tests/00_tmp.py Normal file
View 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}

View File

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

View File

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

View File

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

View File

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