mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-25 22:10:17 +00:00
Compare commits
6 Commits
79012a6b08
...
b8fc853cb8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8fc853cb8 | ||
|
|
6bcff00990 | ||
|
|
31c95c7ba2 | ||
|
|
29aa3e5eed | ||
|
|
1a9bad4e54 | ||
|
|
a4718a00b2 |
@ -42,20 +42,22 @@ void c11_string__ctor2(c11_string* self, const char* data, int size);
|
||||
c11_string* c11_string__copy(c11_string* self);
|
||||
void c11_string__delete(c11_string* self);
|
||||
c11_sv c11_string__sv(c11_string* self);
|
||||
c11_string* c11_string__replace(c11_string* self, char old, char new_);
|
||||
|
||||
int c11_string__u8_length(c11_string* self);
|
||||
c11_sv c11_string__u8_getitem(c11_string* self, int i);
|
||||
c11_string* c11_string__u8_slice(c11_string* self, int start, int stop, int step);
|
||||
int c11_sv__u8_length(c11_sv self);
|
||||
c11_sv c11_sv__u8_getitem(c11_sv self, int i);
|
||||
c11_string* c11_sv__u8_slice(c11_sv self, int start, int stop, int step);
|
||||
|
||||
// general string operations
|
||||
c11_sv c11_sv__slice(c11_sv sv, int start);
|
||||
c11_sv c11_sv__slice2(c11_sv sv, int start, int stop);
|
||||
c11_sv c11_sv__strip(c11_sv sv, bool left, bool right);
|
||||
c11_sv c11_sv__strip(c11_sv sv, c11_sv chars, bool left, bool right);
|
||||
int c11_sv__index(c11_sv self, char c);
|
||||
int c11_sv__index2(c11_sv self, c11_sv sub, int start);
|
||||
int c11_sv__count(c11_sv self, c11_sv sub);
|
||||
|
||||
c11_string* c11_sv__replace(c11_sv self, char old, char new_);
|
||||
c11_string* c11_sv__replace2(c11_sv self, c11_sv old, c11_sv new_);
|
||||
|
||||
c11_vector/* T=c11_sv */ c11_sv__split(c11_sv self, char sep);
|
||||
c11_vector/* T=c11_sv */ c11_sv__split2(c11_sv self, c11_sv sep);
|
||||
|
||||
|
||||
@ -70,6 +70,9 @@ void pk_VM__dtor(pk_VM* self);
|
||||
void pk_VM__push_frame(pk_VM* self, Frame* frame);
|
||||
void pk_VM__pop_frame(pk_VM* self);
|
||||
|
||||
bool pk__parse_int_slice(const py_Ref slice, int length, int* start, int* stop, int* step);
|
||||
bool pk__normalize_index(int* index, int length);
|
||||
|
||||
typedef enum pk_FrameResult {
|
||||
RES_RETURN,
|
||||
RES_CALL,
|
||||
@ -93,6 +96,7 @@ const char* pk_opname(Opcode op);
|
||||
void pk_object__register();
|
||||
void pk_number__register();
|
||||
py_Type pk_str__register();
|
||||
py_Type pk_str_iterator__register();
|
||||
py_Type pk_bytes__register();
|
||||
py_Type pk_list__register();
|
||||
py_Type pk_function__register();
|
||||
|
||||
@ -244,6 +244,8 @@ void py_formatexc(char* out);
|
||||
#define TypeError(...) py_exception("TypeError", __VA_ARGS__)
|
||||
#define ValueError(...) py_exception("ValueError", __VA_ARGS__)
|
||||
#define IndexError(...) py_exception("IndexError", __VA_ARGS__)
|
||||
#define StopIteration() py_exception("StopIteration", "")
|
||||
#define NotImplementedError() py_exception("NotImplementedError", "")
|
||||
#define AttributeError(self, n) \
|
||||
py_exception("AttributeError", "'%t' object has no attribute '%n'", (self)->type, (n))
|
||||
#define UnboundLocalError(n) \
|
||||
@ -264,6 +266,12 @@ int py_gt(const py_Ref, const py_Ref);
|
||||
|
||||
bool py_hash(const py_Ref, py_i64* out);
|
||||
|
||||
/// Get the iterator of the object.
|
||||
bool py_iter(const py_Ref);
|
||||
/// Get the next element from the iterator.
|
||||
/// 1: success, 0: StopIteration, -1: error
|
||||
int py_next(const py_Ref);
|
||||
|
||||
/// Python equivalent to `lhs is rhs`.
|
||||
bool py_isidentical(const py_Ref, const py_Ref);
|
||||
|
||||
@ -296,6 +304,7 @@ bool py_str(py_Ref val);
|
||||
py_GlobalRef py_retval();
|
||||
|
||||
#define py_isnil(self) ((self)->type == 0)
|
||||
#define py_isnone(self) ((self)->type == tp_none_type)
|
||||
|
||||
/* tuple */
|
||||
|
||||
@ -331,9 +340,17 @@ py_GlobalRef py_tpobject(py_Type type);
|
||||
/// Get the type name.
|
||||
const char* py_tpname(py_Type type);
|
||||
|
||||
/// Call a type to create a new instance.
|
||||
bool py_tpcall(py_Type type, int argc, py_Ref argv);
|
||||
|
||||
/// Check if the object is an instance of the given type.
|
||||
bool py_checktype(const py_Ref self, py_Type type);
|
||||
|
||||
#define py_checkint(self) py_checktype(self, tp_int)
|
||||
#define py_checkfloat(self) py_checktype(self, tp_float)
|
||||
#define py_checkbool(self) py_checktype(self, tp_bool)
|
||||
#define py_checkstr(self) py_checktype(self, tp_str)
|
||||
|
||||
int py_replinput(char* buf);
|
||||
|
||||
/// Python favored string formatting.
|
||||
@ -363,6 +380,7 @@ enum py_PredefinedTypes {
|
||||
tp_float,
|
||||
tp_bool,
|
||||
tp_str,
|
||||
tp_str_iterator,
|
||||
tp_list, // c11_vector
|
||||
tp_tuple, // N slots
|
||||
tp_slice, // 3 slots (start, stop, step)
|
||||
@ -384,7 +402,7 @@ enum py_PredefinedTypes {
|
||||
tp_not_implemented_type,
|
||||
tp_ellipsis,
|
||||
tp_syntax_error,
|
||||
tp_stop_iteration
|
||||
tp_stop_iteration,
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@ -38,8 +38,8 @@ void c11_string__delete(c11_string* self) { free(self); }
|
||||
|
||||
c11_sv c11_string__sv(c11_string* self) { return (c11_sv){self->data, self->size}; }
|
||||
|
||||
c11_string* c11_string__replace(c11_string* self, char old, char new_) {
|
||||
c11_string* retval = c11_string__copy(self);
|
||||
c11_string* c11_sv__replace(c11_sv self, char old, char new_) {
|
||||
c11_string* retval = c11_string__new2(self.data, self.size);
|
||||
char* p = (char*)retval->data;
|
||||
for(int i = 0; i < retval->size; i++) {
|
||||
if(p[i] == old) p[i] = new_;
|
||||
@ -47,22 +47,37 @@ c11_string* c11_string__replace(c11_string* self, char old, char new_) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
int c11_string__u8_length(c11_string* self) {
|
||||
return c11__byte_index_to_unicode(self->data, self->size);
|
||||
c11_string* c11_sv__replace2(c11_sv self, c11_sv old, c11_sv new_) {
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
int start = 0;
|
||||
while(true) {
|
||||
int i = c11_sv__index2(self, old, start);
|
||||
if(i == -1) break;
|
||||
c11_sv tmp = c11_sv__slice2(self, start, i);
|
||||
c11_sbuf__write_sv(&buf, tmp);
|
||||
c11_sbuf__write_sv(&buf, new_);
|
||||
start = i + old.size;
|
||||
}
|
||||
c11_sv tmp = c11_sv__slice2(self, start, self.size);
|
||||
c11_sbuf__write_sv(&buf, tmp);
|
||||
return c11_sbuf__submit(&buf);
|
||||
}
|
||||
|
||||
c11_sv c11_string__u8_getitem(c11_string* self, int i) {
|
||||
i = c11__unicode_index_to_byte(self->data, i);
|
||||
int size = c11__u8_header(self->data[i], false);
|
||||
return c11_sv__slice2(c11_string__sv(self), i, i + size);
|
||||
int c11_sv__u8_length(c11_sv sv) { return c11__byte_index_to_unicode(sv.data, sv.size); }
|
||||
|
||||
c11_sv c11_sv__u8_getitem(c11_sv sv, int i) {
|
||||
i = c11__unicode_index_to_byte(sv.data, i);
|
||||
int size = c11__u8_header(sv.data[i], false);
|
||||
return c11_sv__slice2(sv, i, i + size);
|
||||
}
|
||||
|
||||
c11_string* c11_string__u8_slice(c11_string* self, int start, int stop, int step) {
|
||||
c11_string* c11_sv__u8_slice(c11_sv sv, int start, int stop, int step) {
|
||||
c11_sbuf ss;
|
||||
c11_sbuf__ctor(&ss);
|
||||
assert(step != 0);
|
||||
for(int i = start; step > 0 ? i < stop : i > stop; i += step) {
|
||||
c11_sv unicode = c11_string__u8_getitem(self, i);
|
||||
c11_sv unicode = c11_sv__u8_getitem(sv, i);
|
||||
c11_sbuf__write_sv(&ss, unicode);
|
||||
}
|
||||
return c11_sbuf__submit(&ss);
|
||||
@ -78,20 +93,28 @@ c11_sv c11_sv__slice2(c11_sv sv, int start, int stop) {
|
||||
return (c11_sv){sv.data + start, stop - start};
|
||||
}
|
||||
|
||||
c11_sv c11_sv__strip(c11_sv sv, bool left, bool right) {
|
||||
c11_sv c11_sv__strip(c11_sv sv, c11_sv chars, bool left, bool right) {
|
||||
int L = 0;
|
||||
int R = sv.size;
|
||||
const char* data = sv.data;
|
||||
int R = c11_sv__u8_length(sv);
|
||||
if(left) {
|
||||
while(L < R && (data[L] == ' ' || data[L] == '\t' || data[L] == '\n' || data[L] == '\r'))
|
||||
while(L < R) {
|
||||
c11_sv tmp = c11_sv__u8_getitem(sv, L);
|
||||
bool found = c11_sv__index2(chars, tmp, 0) != -1;
|
||||
if(!found) break;
|
||||
L++;
|
||||
}
|
||||
}
|
||||
if(right) {
|
||||
while(L < R && (data[R - 1] == ' ' || data[R - 1] == '\t' || data[R - 1] == '\n' ||
|
||||
data[R - 1] == '\r'))
|
||||
while(L < R) {
|
||||
c11_sv tmp = c11_sv__u8_getitem(sv, R - 1);
|
||||
bool found = c11_sv__index2(chars, tmp, 0) != -1;
|
||||
if(!found) break;
|
||||
R--;
|
||||
}
|
||||
}
|
||||
return c11_sv__slice2(sv, L, R);
|
||||
int start = c11__unicode_index_to_byte(sv.data, L);
|
||||
int stop = c11__unicode_index_to_byte(sv.data, R);
|
||||
return c11_sv__slice2(sv, start, stop);
|
||||
}
|
||||
|
||||
int c11_sv__index(c11_sv self, char c) {
|
||||
|
||||
@ -753,5 +753,7 @@ bool py_binaryop(const py_Ref lhs, const py_Ref rhs, py_Name op, py_Name rop) {
|
||||
pk_VM* self = pk_current_vm;
|
||||
PUSH(lhs);
|
||||
PUSH(rhs);
|
||||
return stack_binaryop(self, op, rop);
|
||||
bool ok = stack_binaryop(self, op, rop);
|
||||
STACK_SHRINK(2);
|
||||
return ok;
|
||||
}
|
||||
@ -96,6 +96,7 @@ void pk_VM__ctor(pk_VM* self) {
|
||||
pk_number__register();
|
||||
|
||||
validate(tp_str, pk_str__register());
|
||||
validate(tp_str_iterator, pk_str_iterator__register());
|
||||
|
||||
validate(tp_list, pk_list__register());
|
||||
validate(tp_tuple, pk_VM__new_type(self, "tuple", tp_object, NULL, false));
|
||||
@ -189,6 +190,70 @@ void pk_VM__pop_frame(pk_VM* self) {
|
||||
Frame__delete(frame);
|
||||
}
|
||||
|
||||
static void _clip_int(int* value, int min, int max) {
|
||||
if(*value < min) *value = min;
|
||||
if(*value > max) *value = max;
|
||||
}
|
||||
|
||||
bool pk__parse_int_slice(const py_Ref slice, int length, int* start, int* stop, int* step) {
|
||||
py_Ref s_start = py_getslot(slice, 0);
|
||||
py_Ref s_stop = py_getslot(slice, 1);
|
||||
py_Ref s_step = py_getslot(slice, 2);
|
||||
|
||||
if(py_isnone(s_step))
|
||||
*step = 1;
|
||||
else {
|
||||
if(!py_checkint(s_step)) return false;
|
||||
*step = py_toint(s_step);
|
||||
}
|
||||
if(*step == 0) return ValueError("slice step cannot be zero");
|
||||
|
||||
if(*step > 0) {
|
||||
if(py_isnone(s_start))
|
||||
*start = 0;
|
||||
else {
|
||||
if(!py_checkint(s_start)) return false;
|
||||
*start = py_toint(s_start);
|
||||
if(*start < 0) *start += length;
|
||||
_clip_int(start, 0, length);
|
||||
}
|
||||
if(py_isnone(s_stop))
|
||||
*stop = length;
|
||||
else {
|
||||
if(!py_checkint(s_stop)) return false;
|
||||
*stop = py_toint(s_stop);
|
||||
if(*stop < 0) *stop += length;
|
||||
_clip_int(stop, 0, length);
|
||||
}
|
||||
} else {
|
||||
if(py_isnone(s_start))
|
||||
*start = length - 1;
|
||||
else {
|
||||
if(!py_checkint(s_start)) return false;
|
||||
*start = py_toint(s_start);
|
||||
if(*start < 0) *start += length;
|
||||
_clip_int(start, -1, length - 1);
|
||||
}
|
||||
if(py_isnone(s_stop))
|
||||
*stop = -1;
|
||||
else {
|
||||
if(!py_checkint(s_stop)) return false;
|
||||
*stop = py_toint(s_stop);
|
||||
if(*stop < 0) *stop += length;
|
||||
_clip_int(stop, -1, length - 1);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pk__normalize_index(int *index, int length){
|
||||
if(*index < 0) *index += length;
|
||||
if(*index < 0 || *index >= length){
|
||||
return IndexError("index out of range");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
py_Type pk_VM__new_type(pk_VM* self,
|
||||
const char* name,
|
||||
py_Type base,
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
|
||||
typedef c11_vector List;
|
||||
|
||||
|
||||
void py_newlist(py_Ref out) {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
PyObject* obj = pk_ManagedHeap__gcnew(&vm->heap, tp_list, 0, sizeof(List));
|
||||
@ -60,13 +59,118 @@ void py_list__insert(py_Ref self, int i, const py_Ref val) {
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
static bool _py_list__len__(int argc, py_Ref argv){
|
||||
static bool _py_list__len__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
py_i64 res = py_list__len(py_arg(0));
|
||||
py_newint(py_retval(), res);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_list__eq__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
py_Ref _0 = py_arg(0);
|
||||
py_Ref _1 = py_arg(1);
|
||||
if(py_istype(_1, tp_list)) {
|
||||
int length = py_list__len(_0);
|
||||
if(length != py_list__len(_1)) {
|
||||
py_newbool(py_retval(), false);
|
||||
return true;
|
||||
}
|
||||
for(int i = 0; i < length; i++) {
|
||||
py_Ref a = py_list__getitem(_0, i);
|
||||
py_Ref b = py_list__getitem(_1, i);
|
||||
int res = py_eq(a, b);
|
||||
if(res == -1) return false;
|
||||
if(res == 0) {
|
||||
py_newbool(py_retval(), false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
py_newbool(py_retval(), true);
|
||||
} else {
|
||||
py_newnotimplemented(py_retval());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_list__ne__(int argc, py_Ref argv) {
|
||||
bool ok = _py_list__eq__(argc, argv);
|
||||
if(!ok) return false;
|
||||
py_Ref retval = py_retval();
|
||||
py_newbool(retval, !py_tobool(retval));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_list__new__(int argc, py_Ref argv) {
|
||||
if(argc == 1) {
|
||||
py_newlist(py_retval());
|
||||
return true;
|
||||
}
|
||||
if(argc == 2) {
|
||||
py_Ref iter = py_pushtmp();
|
||||
py_Ref list = py_pushtmp();
|
||||
if(!py_iter(py_arg(1))) return false;
|
||||
*iter = *py_retval();
|
||||
py_newlist(list);
|
||||
while(true) {
|
||||
int res = py_next(iter);
|
||||
if(res == -1) return false;
|
||||
if(res) {
|
||||
py_list__append(list, py_retval());
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*py_retval() = *list;
|
||||
return true;
|
||||
}
|
||||
return TypeError("list() takes at most 1 argument");
|
||||
}
|
||||
|
||||
static bool _py_list__getitem__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
List* self = py_touserdata(py_arg(0));
|
||||
py_Ref _1 = py_arg(1);
|
||||
if(_1->type == tp_int) {
|
||||
int index = py_toint(py_arg(1));
|
||||
if(!pk__normalize_index(&index, self->count)) return false;
|
||||
*py_retval() = c11__getitem(py_TValue, self, index);
|
||||
return true;
|
||||
} else if(_1->type == tp_slice) {
|
||||
int start, stop, step;
|
||||
bool ok = pk__parse_int_slice(_1, self->count, &start, &stop, &step);
|
||||
if(!ok) return false;
|
||||
py_newlist(py_retval());
|
||||
List* list = py_touserdata(py_retval());
|
||||
PK_SLICE_LOOP(i, start, stop, step) {
|
||||
c11_vector__push(py_TValue, list, c11__getitem(py_TValue, self, i));
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return TypeError("list indices must be integers");
|
||||
}
|
||||
}
|
||||
|
||||
static bool _py_list__setitem__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(3);
|
||||
PY_CHECK_ARG_TYPE(1, tp_int);
|
||||
List* self = py_touserdata(py_arg(0));
|
||||
int index = py_toint(py_arg(1));
|
||||
if(!pk__normalize_index(&index, self->count)) return false;
|
||||
c11__setitem(py_TValue, self, index, *py_arg(2));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_list__delitem__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
PY_CHECK_ARG_TYPE(1, tp_int);
|
||||
List* self = py_touserdata(py_arg(0));
|
||||
int index = py_toint(py_arg(1));
|
||||
if(!pk__normalize_index(&index, self->count)) return false;
|
||||
c11_vector__erase(py_TValue, self, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
py_Type pk_list__register() {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
py_Type type = pk_VM__new_type(vm, "list", tp_object, NULL, false);
|
||||
@ -74,5 +178,11 @@ py_Type pk_list__register() {
|
||||
ti->dtor = (void (*)(void*))c11_vector__dtor;
|
||||
|
||||
py_bindmagic(type, __len__, _py_list__len__);
|
||||
py_bindmagic(type, __eq__, _py_list__eq__);
|
||||
py_bindmagic(type, __ne__, _py_list__ne__);
|
||||
py_bindmagic(type, __new__, _py_list__new__);
|
||||
py_bindmagic(type, __getitem__, _py_list__getitem__);
|
||||
py_bindmagic(type, __setitem__, _py_list__setitem__);
|
||||
py_bindmagic(type, __delitem__, _py_list__delitem__);
|
||||
return type;
|
||||
}
|
||||
@ -60,6 +60,24 @@ bool py_hash(const py_Ref val, int64_t* out) {
|
||||
return TypeError("unhashable type: '%t'", val->type);
|
||||
}
|
||||
|
||||
bool py_iter(const py_Ref val) {
|
||||
py_Ref tmp = py_tpfindmagic(val->type, __iter__);
|
||||
if(!tmp) return TypeError("'%t' object is not iterable", val->type);
|
||||
return py_call(tmp, 1, val);
|
||||
}
|
||||
|
||||
int py_next(const py_Ref val) {
|
||||
py_Ref tmp = py_tpfindmagic(val->type, __next__);
|
||||
if(!tmp) return TypeError("'%t' object is not an iterator", val->type);
|
||||
bool ok = py_call(tmp, 1, val);
|
||||
if(ok) {
|
||||
py_Ref retval = py_retval();
|
||||
bool is_end = retval->type == tp_type && py_totype(retval) == tp_stop_iteration;
|
||||
return !is_end;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int py_getattr(const py_Ref self, py_Name name, py_Ref out) { return -1; }
|
||||
|
||||
bool py_setattr(py_Ref self, py_Name name, const py_Ref val) { return false; }
|
||||
|
||||
@ -158,17 +158,30 @@ static bool _py_str__repr__(int argc, py_Ref argv) {
|
||||
|
||||
static bool _py_str__iter__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
assert(false);
|
||||
return false;
|
||||
return py_tpcall(tp_str_iterator, 1, argv);
|
||||
}
|
||||
|
||||
static bool _py_str__getitem__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
c11_string* self = py_touserdata(&argv[0]);
|
||||
PY_CHECK_ARG_TYPE(1, tp_int);
|
||||
c11_sv res = c11_string__u8_getitem(self, py_toint(py_arg(1)));
|
||||
py_newstrn(py_retval(), res.data, res.size);
|
||||
return true;
|
||||
c11_sv self = c11_string__sv(py_touserdata(&argv[0]));
|
||||
py_Ref _1 = py_arg(1);
|
||||
if(_1->type == tp_int) {
|
||||
int index = py_toint(py_arg(1));
|
||||
if(!pk__normalize_index(&index, self.size)) return false;
|
||||
c11_sv res = c11_sv__u8_getitem(self, index);
|
||||
py_newstrn(py_retval(), res.data, res.size);
|
||||
return true;
|
||||
} else if(_1->type == tp_slice) {
|
||||
int start, stop, step;
|
||||
bool ok = pk__parse_int_slice(_1, c11_sv__u8_length(self), &start, &stop, &step);
|
||||
if(!ok) return false;
|
||||
c11_string* res = c11_sv__u8_slice(self, start, stop, step);
|
||||
py_newstrn(py_retval(), res->data, res->size);
|
||||
c11_string__delete(res);
|
||||
return true;
|
||||
} else {
|
||||
return TypeError("string indices must be integers");
|
||||
}
|
||||
}
|
||||
|
||||
#define DEF_STR_CMP_OP(op, __f, __cond) \
|
||||
@ -247,14 +260,202 @@ static bool _py_str__endswith(int argc, py_Ref argv) {
|
||||
}
|
||||
|
||||
static bool _py_str__join(int argc, py_Ref argv) {
|
||||
assert(false);
|
||||
// PY_CHECK_ARGC(2);
|
||||
// c11_sbuf buf;
|
||||
// c11_sbuf__ctor(&buf);
|
||||
// c11_string* sep = py_touserdata(&argv[0]);
|
||||
// py_Ref iter = py_pushtmp();
|
||||
// py_iter(iter, &argv[1]);
|
||||
return false;
|
||||
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_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])) {
|
||||
c11_sbuf__dtor(&buf);
|
||||
return false;
|
||||
}
|
||||
c11_string* item = py_touserdata(&p[i]);
|
||||
c11_sbuf__write_cstrn(&buf, item->data, item->size);
|
||||
}
|
||||
c11_string* res = c11_sbuf__submit(&buf);
|
||||
py_newstrn(py_retval(), res->data, res->size);
|
||||
c11_string__delete(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_str__replace(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(3);
|
||||
c11_string* self = py_touserdata(&argv[0]);
|
||||
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||
PY_CHECK_ARG_TYPE(2, tp_str);
|
||||
c11_string* old = py_touserdata(&argv[1]);
|
||||
c11_string* new_ = py_touserdata(&argv[2]);
|
||||
c11_string* res =
|
||||
c11_sv__replace2(c11_string__sv(self), c11_string__sv(old), c11_string__sv(new_));
|
||||
py_newstrn(py_retval(), res->data, res->size);
|
||||
c11_string__delete(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_str__split(int argc, py_Ref argv) {
|
||||
c11_sv self = c11_string__sv(py_touserdata(&argv[0]));
|
||||
c11_vector res;
|
||||
if(argc > 2) return TypeError("split() takes at most 2 arguments");
|
||||
if(argc == 1) {
|
||||
// sep = ' '
|
||||
res = c11_sv__split(self, ' ');
|
||||
}
|
||||
if(argc == 2) {
|
||||
// sep = argv[1]
|
||||
if(!py_checkstr(&argv[1])) return false;
|
||||
c11_sv sep = c11_string__sv(py_touserdata(&argv[1]));
|
||||
res = c11_sv__split2(self, sep);
|
||||
}
|
||||
py_newlistn(py_retval(), res.count);
|
||||
for(int i = 0; i < res.count; i++) {
|
||||
c11_sv item = c11__getitem(c11_sv, &res, i);
|
||||
py_newstrn(py_list__getitem(py_retval(), i), item.data, item.size);
|
||||
}
|
||||
c11_vector__dtor(&res);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_str__count(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
c11_string* self = py_touserdata(&argv[0]);
|
||||
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||
c11_string* sub = py_touserdata(&argv[1]);
|
||||
int res = c11_sv__count(c11_string__sv(self), c11_string__sv(sub));
|
||||
py_newint(py_retval(), res);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_str__strip_impl(bool left, bool right, int argc, py_Ref argv) {
|
||||
c11_sv self = c11_string__sv(py_touserdata(&argv[0]));
|
||||
c11_sv chars;
|
||||
if(argc == 1) {
|
||||
chars = (c11_sv){" \t\n\r", 4};
|
||||
} else if(argc == 2) {
|
||||
if(!py_checkstr(&argv[1])) return false;
|
||||
chars = c11_string__sv(py_touserdata(&argv[1]));
|
||||
} else {
|
||||
return TypeError("strip() takes at most 2 arguments");
|
||||
}
|
||||
c11_sv res = c11_sv__strip(self, chars, left, right);
|
||||
py_newstrn(py_retval(), res.data, res.size);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_str__strip(int argc, py_Ref argv) {
|
||||
return _py_str__strip_impl(true, true, argc, argv);
|
||||
}
|
||||
|
||||
static bool _py_str__lstrip(int argc, py_Ref argv) {
|
||||
return _py_str__strip_impl(true, false, argc, argv);
|
||||
}
|
||||
|
||||
static bool _py_str__rstrip(int argc, py_Ref argv) {
|
||||
return _py_str__strip_impl(false, true, argc, argv);
|
||||
}
|
||||
|
||||
static bool _py_str__zfill(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
c11_sv self = c11_string__sv(py_touserdata(&argv[0]));
|
||||
PY_CHECK_ARG_TYPE(1, tp_int);
|
||||
int width = py_toint(py_arg(1));
|
||||
int delta = width - c11_sv__u8_length(self);
|
||||
if(delta <= 0) {
|
||||
*py_retval() = argv[0];
|
||||
return true;
|
||||
}
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
for(int i = 0; i < delta; i++) {
|
||||
c11_sbuf__write_char(&buf, '0');
|
||||
}
|
||||
c11_sbuf__write_sv(&buf, self);
|
||||
c11_string* res = c11_sbuf__submit(&buf);
|
||||
py_newstrn(py_retval(), res->data, res->size);
|
||||
c11_string__delete(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_str__widthjust_impl(bool left, int argc, py_Ref argv) {
|
||||
if(argc > 1 + 2) return TypeError("expected at most 2 arguments");
|
||||
char pad;
|
||||
if(argc == 1 + 1) {
|
||||
pad = ' ';
|
||||
} else {
|
||||
if(!py_checkstr(&argv[2])) return false;
|
||||
c11_string* padstr = py_touserdata(&argv[2]);
|
||||
if(padstr->size != 1)
|
||||
return TypeError("The fill character must be exactly one character long");
|
||||
pad = padstr->data[0];
|
||||
}
|
||||
c11_sv self = c11_string__sv(py_touserdata(&argv[0]));
|
||||
PY_CHECK_ARG_TYPE(1, tp_int);
|
||||
int width = py_toint(py_arg(1));
|
||||
if(width <= self.size) {
|
||||
*py_retval() = argv[0];
|
||||
return true;
|
||||
}
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
if(left) {
|
||||
c11_sbuf__write_sv(&buf, self);
|
||||
for(int i = 0; i < width - self.size; i++) {
|
||||
c11_sbuf__write_char(&buf, pad);
|
||||
}
|
||||
} else {
|
||||
for(int i = 0; i < width - self.size; i++) {
|
||||
c11_sbuf__write_char(&buf, pad);
|
||||
}
|
||||
c11_sbuf__write_sv(&buf, self);
|
||||
}
|
||||
c11_string* res = c11_sbuf__submit(&buf);
|
||||
py_newstrn(py_retval(), res->data, res->size);
|
||||
c11_string__delete(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_str__ljust(int argc, py_Ref argv) {
|
||||
return _py_str__widthjust_impl(true, argc, argv);
|
||||
}
|
||||
|
||||
static bool _py_str__rjust(int argc, py_Ref argv) {
|
||||
return _py_str__widthjust_impl(false, argc, argv);
|
||||
}
|
||||
|
||||
static bool _py_str__find(int argc, py_Ref argv) {
|
||||
if(argc > 3) return TypeError("find() takes at most 3 arguments");
|
||||
int start = 0;
|
||||
if(argc == 3) {
|
||||
PY_CHECK_ARG_TYPE(2, tp_int);
|
||||
start = py_toint(py_arg(2));
|
||||
}
|
||||
c11_string* self = py_touserdata(&argv[0]);
|
||||
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||
c11_string* sub = py_touserdata(&argv[1]);
|
||||
int res = c11_sv__index2(c11_string__sv(self), c11_string__sv(sub), start);
|
||||
py_newint(py_retval(), res);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_str__index(int argc, py_Ref argv) {
|
||||
bool ok = _py_str__find(argc, argv);
|
||||
if(!ok) return false;
|
||||
if(py_toint(py_retval()) == -1) return ValueError("substring not found");
|
||||
return true;
|
||||
}
|
||||
|
||||
py_Type pk_str__register() {
|
||||
@ -286,6 +487,57 @@ py_Type pk_str__register() {
|
||||
py_bindmethod(tp_str, "startswith", _py_str__startswith);
|
||||
py_bindmethod(tp_str, "endswith", _py_str__endswith);
|
||||
py_bindmethod(tp_str, "join", _py_str__join);
|
||||
py_bindmethod(tp_str, "replace", _py_str__replace);
|
||||
py_bindmethod(tp_str, "split", _py_str__split);
|
||||
py_bindmethod(tp_str, "count", _py_str__count);
|
||||
py_bindmethod(tp_str, "strip", _py_str__strip);
|
||||
py_bindmethod(tp_str, "lstrip", _py_str__lstrip);
|
||||
py_bindmethod(tp_str, "rstrip", _py_str__rstrip);
|
||||
py_bindmethod(tp_str, "zfill", _py_str__zfill);
|
||||
py_bindmethod(tp_str, "ljust", _py_str__ljust);
|
||||
py_bindmethod(tp_str, "rjust", _py_str__rjust);
|
||||
py_bindmethod(tp_str, "find", _py_str__find);
|
||||
py_bindmethod(tp_str, "index", _py_str__index);
|
||||
return type;
|
||||
}
|
||||
|
||||
static bool _py_str_iterator__new__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(2);
|
||||
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||
int* ud = py_newobject(py_retval(), tp_str_iterator, 1, sizeof(int));
|
||||
*ud = 0;
|
||||
py_setslot(py_retval(), 0, &argv[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_str_iterator__iter__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
*py_retval() = argv[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_str_iterator__next__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
int* ud = py_touserdata(&argv[0]);
|
||||
int size;
|
||||
const char* data = py_tostrn(py_getslot(argv, 0), &size);
|
||||
if(*ud == size) {
|
||||
*py_retval() = pk_current_vm->StopIteration;
|
||||
return true;
|
||||
}
|
||||
int start = *ud;
|
||||
int len = c11__u8_header(data[*ud], false);
|
||||
*ud += len;
|
||||
py_newstrn(py_retval(), data + start, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
py_Type pk_str_iterator__register() {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
py_Type type = pk_VM__new_type(vm, "str_iterator", tp_object, NULL, false);
|
||||
py_bindmagic(type, __new__, _py_str_iterator__new__);
|
||||
py_bindmagic(type, __iter__, _py_str_iterator__iter__);
|
||||
py_bindmagic(type, __next__, _py_str_iterator__next__);
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
@ -197,7 +197,9 @@ bool py_call(py_Ref f, int argc, py_Ref argv) {
|
||||
py_pushnil();
|
||||
for(int i = 0; i < argc; i++)
|
||||
py_push(py_offset(argv, i));
|
||||
return pk_VM__vectorcall(vm, argc, 0, false) == RES_ERROR;
|
||||
pk_FrameResult res = pk_VM__vectorcall(vm, argc, 0, false);
|
||||
assert(res == RES_ERROR || res == RES_RETURN);
|
||||
return res == RES_RETURN;
|
||||
}
|
||||
}
|
||||
|
||||
@ -292,6 +294,10 @@ const char* py_tpname(py_Type type) {
|
||||
return py_name2str(name);
|
||||
}
|
||||
|
||||
bool py_tpcall(py_Type type, int argc, py_Ref argv){
|
||||
return py_call(py_tpobject(type), argc, argv);
|
||||
}
|
||||
|
||||
bool py_callmagic(py_Name name, int argc, py_Ref argv) {
|
||||
assert(argc >= 1);
|
||||
assert(py_ismagicname(name));
|
||||
|
||||
107
tests/04_str.py
107
tests/04_str.py
@ -101,10 +101,6 @@ assert s2.join( seq ) == "runoob"
|
||||
assert 'x'.zfill(5) == '0000x'
|
||||
assert '568'.zfill(1) == '568'
|
||||
|
||||
def test(*seq):
|
||||
return s1.join(seq)
|
||||
assert test("r", "u", "n", "o", "o", "b") == "r-u-n-o-o-b"
|
||||
|
||||
num = 6
|
||||
assert str(num) == '6'
|
||||
|
||||
@ -112,55 +108,6 @@ assert str(num) == '6'
|
||||
测试 = "test"
|
||||
assert 测试 == "test"
|
||||
|
||||
# 3rd slice
|
||||
a = "Hello, World!"
|
||||
assert a[::-1] == "!dlroW ,olleH"
|
||||
assert a[::2] == "Hlo ol!"
|
||||
assert a[2:5:2] == "lo"
|
||||
assert a[5:2:-1] == ",ol"
|
||||
assert a[5:2:-2] == ",l"
|
||||
|
||||
b = list(a)
|
||||
assert b == ['H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!']
|
||||
assert b[::-1] == ['!', 'd', 'l', 'r', 'o', 'W', ' ', ',', 'o', 'l', 'l', 'e', 'H']
|
||||
assert b[::2] == ['H', 'l', 'o', ' ', 'o', 'l', '!']
|
||||
assert b[2:5:2] == ['l', 'o']
|
||||
assert b[5:2:-1] == [',', 'o', 'l']
|
||||
assert b[5:2:-2] == [',', 'l']
|
||||
|
||||
a = '123'
|
||||
assert a.rjust(5) == ' 123'
|
||||
assert a.rjust(5, '0') == '00123'
|
||||
assert a.ljust(5) == '123 '
|
||||
assert a.ljust(5, '0') == '12300'
|
||||
|
||||
assert '\x30\x31\x32' == '012'
|
||||
assert '\b\b\b' == '\x08\x08\x08'
|
||||
assert repr('\x1f\x1e\x1f') == '\'\\x1f\\x1e\\x1f\''
|
||||
|
||||
assert hex(-42) == '-0x2a'
|
||||
assert hex(42) == '0x2a'
|
||||
|
||||
assert hex(0) == '0x0'
|
||||
assert hex(1) == '0x1'
|
||||
assert hex(15) == '0xf'
|
||||
assert hex(16) == '0x10'
|
||||
assert hex(255) == '0xff'
|
||||
assert hex(256) == '0x100'
|
||||
assert hex(257) == '0x101'
|
||||
assert hex(17) == '0x11'
|
||||
|
||||
a = '123'
|
||||
assert a.index('2') == 1
|
||||
assert a.index('1') == 0
|
||||
assert a.index('3') == 2
|
||||
|
||||
assert a.index('2', 1) == 1
|
||||
assert a.index('1', 0) == 0
|
||||
|
||||
assert a.find('1') == 0
|
||||
assert a.find('1', 1) == -1
|
||||
|
||||
a = 'abcd'
|
||||
assert list(a) == ['a', 'b', 'c', 'd']
|
||||
a = '测试'
|
||||
@ -178,6 +125,60 @@ assert list(a) == ['b']
|
||||
a = '测'
|
||||
assert list(a) == ['测']
|
||||
|
||||
# 3rd slice
|
||||
a = "Hello, World!"
|
||||
assert a[::-1] == "!dlroW ,olleH"
|
||||
assert a[::2] == "Hlo ol!"
|
||||
assert a[2:5:2] == "lo"
|
||||
assert a[5:2:-1] == ",ol"
|
||||
assert a[5:2:-2] == ",l"
|
||||
|
||||
a = '123'
|
||||
assert a.rjust(5) == ' 123'
|
||||
assert a.rjust(5, '0') == '00123'
|
||||
assert a.ljust(5) == '123 '
|
||||
assert a.ljust(5, '0') == '12300'
|
||||
|
||||
assert '\x30\x31\x32' == '012'
|
||||
assert '\b\b\b' == '\x08\x08\x08'
|
||||
assert repr('\x1f\x1e\x1f') == '\'\\x1f\\x1e\\x1f\''
|
||||
|
||||
a = '123'
|
||||
assert a.index('2') == 1
|
||||
assert a.index('1') == 0
|
||||
assert a.index('3') == 2
|
||||
assert a.index('23') == 1
|
||||
|
||||
assert a.index('2', 1) == 1
|
||||
assert a.index('1', 0) == 0
|
||||
|
||||
assert a.find('1') == 0
|
||||
assert a.find('1', 1) == -1
|
||||
|
||||
b = list("Hello, World!")
|
||||
assert b == ['H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!']
|
||||
assert b[::-1] == ['!', 'd', 'l', 'r', 'o', 'W', ' ', ',', 'o', 'l', 'l', 'e', 'H']
|
||||
assert b[::2] == ['H', 'l', 'o', ' ', 'o', 'l', '!']
|
||||
assert b[2:5:2] == ['l', 'o']
|
||||
assert b[5:2:-1] == [',', 'o', 'l']
|
||||
assert b[5:2:-2] == [',', 'l']
|
||||
|
||||
assert hex(-42) == '-0x2a'
|
||||
assert hex(42) == '0x2a'
|
||||
|
||||
assert hex(0) == '0x0'
|
||||
assert hex(1) == '0x1'
|
||||
assert hex(15) == '0xf'
|
||||
assert hex(16) == '0x10'
|
||||
assert hex(255) == '0xff'
|
||||
assert hex(256) == '0x100'
|
||||
assert hex(257) == '0x101'
|
||||
assert hex(17) == '0x11'
|
||||
|
||||
def test(*seq):
|
||||
return s1.join(seq)
|
||||
assert test("r", "u", "n", "o", "o", "b") == "r-u-n-o-o-b"
|
||||
|
||||
# test format()
|
||||
assert "Hello, {}!".format("World") == "Hello, World!"
|
||||
assert "{} {} {}".format("I", "love", "Python") == "I love Python"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user