mirror of
				https://github.com/pocketpy/pocketpy
				synced 2025-10-31 08:50: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