11 #define CURRENT_CTYPE KrkString *
12 #define CURRENT_NAME self
14 #define AT_END() (self->length == 0 || i == self->length - 1)
16 #define KRK_STRING_FAST(string,offset) (uint32_t)\
17 ((string->obj.flags & KRK_OBJ_FLAGS_STRING_MASK) <= (KRK_OBJ_FLAGS_STRING_UCS1) ? ((uint8_t*)string->codes)[offset] : \
18 ((string->obj.flags & KRK_OBJ_FLAGS_STRING_MASK) == (KRK_OBJ_FLAGS_STRING_UCS2) ? ((uint16_t*)string->codes)[offset] : \
19 ((uint32_t*)string->codes)[offset]))
21 #define CODEPOINT_BYTES(cp) (cp < 0x80 ? 1 : (cp < 0x800 ? 2 : (cp < 0x10000 ? 3 : 4)))
23 KRK_Method(str,__ord__) {
25 if (self->codesLength != 1)
26 return krk_runtimeError(
vm.exceptions->typeError,
"ord() expected a character, but string of length %d found", (
int)self->codesLength);
30 KRK_StaticMethod(str,__new__) {
33 return OBJECT_VAL(S(
""));
35 FUNCTION_TAKES_AT_MOST(2);
36 if (IS_STRING(argv[1]))
return argv[1];
43 KRK_Method(str,__add__) {
44 METHOD_TAKES_EXACTLY(1);
52 a = AS_CSTRING(argv[0]);
55 b = AS_CSTRING(argv[1]);
58 size_t length = al + bl;
59 char * chars = KRK_ALLOCATE(
char, length + 1);
61 memcpy(chars + al, b, bl);
64 size_t cpLength =
self->codesLength + them->codesLength;
66 int self_type = (
self->obj.flags & KRK_OBJ_FLAGS_STRING_MASK);
67 int them_type = (them->obj.flags & KRK_OBJ_FLAGS_STRING_MASK);
69 KrkStringType type = self_type > them_type ? self_type : them_type;
72 uint32_t hash =
self->obj.hash;
73 for (
size_t i = 0; i < bl; ++i) {
74 krk_hash_advance(hash,b[i]);
79 return OBJECT_VAL(result);
82 KRK_Method(str,__hash__) {
83 return INTEGER_VAL(self->obj.hash);
86 KRK_Method(str,__len__) {
87 return INTEGER_VAL(self->codesLength);
90 KRK_Method(str,__setitem__) {
95 KRK_Method(str,__int__) {
96 METHOD_TAKES_AT_MOST(1);
97 int base = (argc < 2 || !IS_INTEGER(argv[1])) ? 0 : (
int)AS_INTEGER(argv[1]);
98 return krk_parse_int(AS_CSTRING(argv[0]), AS_STRING(argv[0])->length, base);
102 KRK_Method(str,__float__) {
105 return krk_parse_float(AS_CSTRING(argv[0]),AS_STRING(argv[0])->length);
111 KRK_Method(str,__getitem__) {
112 METHOD_TAKES_EXACTLY(1);
113 if (IS_INTEGER(argv[1])) {
114 CHECK_ARG(1,
int,krk_integer_type,asInt);
115 if (asInt < 0) asInt += (int)AS_STRING(argv[0])->codesLength;
116 if (asInt < 0 || asInt >= (
int)AS_STRING(argv[0])->codesLength) {
117 return krk_runtimeError(
vm.exceptions->indexError,
"String index out of range: " PRIkrk_int, asInt);
119 if ((self->obj.flags & KRK_OBJ_FLAGS_STRING_MASK) == KRK_OBJ_FLAGS_STRING_ASCII) {
123 unsigned char asbytes[5];
127 }
else if (IS_slice(argv[1])) {
128 KRK_SLICER(argv[1], self->codesLength) {
133 long len = end - start;
134 if ((self->obj.flags & KRK_OBJ_FLAGS_STRING_MASK) == KRK_OBJ_FLAGS_STRING_ASCII) {
141 for (
long i = 0; i < start; ++i) {
142 uint32_t cp = KRK_STRING_FAST(
self,i);
143 offset += CODEPOINT_BYTES(cp);
145 for (
long i = start; i < end; ++i) {
146 uint32_t cp = KRK_STRING_FAST(
self,i);
147 length += CODEPOINT_BYTES(cp);
155 unsigned char asbytes[5];
156 krk_integer_type i = start;
158 while ((step < 0) ? (i > end) : (i < end)) {
160 pushStringBuilderStr(&sb, (
char*)asbytes, length);
164 return finishStringBuilder(&sb);
167 return TYPE_ERROR(
int or slice, argv[1]);
171 const char * krk_parseCommonFormatSpec(
struct ParsedFormatSpec *result,
const char * spec,
size_t length);
173 KRK_Method(str,__format__) {
174 METHOD_TAKES_EXACTLY(1);
178 const char * spec = krk_parseCommonFormatSpec(&opts, format_spec->chars, format_spec->length);
179 if (!spec)
return NONE_VAL();
187 "Unknown format code '%c' for object of type '%s'",
195 size_t actualLength =
self->codesLength;
198 if (opts.hasPrecision && (
size_t)opts.prec < actualLength) {
199 actualLength = opts.prec;
205 if (opts.hasWidth && actualLength < (
size_t)opts.width) {
206 if (!opts.align || opts.align ==
'<') {
207 padRight = opts.width - actualLength;
208 }
else if (opts.align ==
'>' || opts.align ==
'=') {
209 padLeft = opts.width - actualLength;
210 }
else if (opts.align ==
'^') {
211 padLeft = (opts.width - actualLength) / 2;
212 padRight = (opts.width - actualLength) - padLeft;
217 if (padLeft == 0 && padRight == 0 && actualLength == self->codesLength) {
224 for (
size_t i = 0; i < padLeft; ++i) {
225 pushStringBuilderStr(&sb, opts.fill, opts.fillSize);
230 for (
size_t i = 0; i < actualLength; ++i) {
231 uint32_t cp = KRK_STRING_FAST(
self,i);
232 size_t bytes = CODEPOINT_BYTES(cp);
233 pushStringBuilderStr(&sb, &self->chars[offset], bytes);
238 for (
size_t i = 0; i < padRight; ++i) {
239 pushStringBuilderStr(&sb, opts.fill, opts.fillSize);
242 return finishStringBuilder(&sb);
246 KRK_Method(str,format) {
255 int counterOffset = 0;
256 char * erroneousField = NULL;
257 int erroneousIndex = -1;
258 const char * errorStr =
"";
260 char * workSpace = strdup(self->chars);
261 char * c = workSpace;
262 for (
size_t i = 0; i <
self->length; i++, c++) {
264 if (!AT_END() && c[1] ==
'{') {
265 pushStringBuilder(&sb,
'{');
271 char * fieldStart = c;
272 char * fieldStop = NULL;
273 for (; i <
self->length; i++, c++) {
280 errorStr =
"Unclosed { found.";
283 size_t fieldLength = fieldStop - fieldStart;
287 for (
char * field = fieldStart; *field; ++field) {
288 if (!(*field >=
'0' && *field <=
'9')) {
296 int positionalOffset;
297 if (fieldLength == 0) {
298 positionalOffset = counterOffset++;
299 }
else if (counterOffset) {
300 goto _formatSwitchedNumbering;
302 positionalOffset = strtoul(fieldStart,NULL,10);
304 if (positionalOffset >= argc - 1) {
305 erroneousIndex = positionalOffset;
306 goto _formatOutOfRange;
308 value = argv[1 + positionalOffset];
312 if (!
krk_tableGet(AS_DICT(kwargs), fieldAsString, &value)) {
313 erroneousField = fieldStart;
314 goto _formatKeyError;
318 erroneousField = fieldStart;
319 goto _formatKeyError;
322 if (IS_STRING(value)) {
331 errorStr =
"Failed to convert field to string.";
336 if (!IS_STRING(asString))
goto _freeAndDone;
339 pushStringBuilderStr(&sb, AS_CSTRING(asString), AS_STRING(asString)->length);
342 }
else if (*c ==
'}') {
343 if (!AT_END() && c[1] ==
'}') {
344 pushStringBuilder(&sb,
'}');
348 errorStr =
"Single } found.";
352 pushStringBuilder(&sb, *c);
357 return finishStringBuilder(&sb);
360 krk_runtimeError(
vm.exceptions->typeError,
"Error parsing format string: %s", errorStr);
363 _formatSwitchedNumbering:
364 krk_runtimeError(
vm.exceptions->valueError,
"Can not switch from automatic indexing to manual indexing");
368 krk_runtimeError(
vm.exceptions->indexError,
"Positional index out of range: %d", erroneousIndex);
377 discardStringBuilder(&sb);
382 KRK_Method(str,__mul__) {
383 METHOD_TAKES_EXACTLY(1);
384 if (!IS_INTEGER(argv[1]))
return NOTIMPL_VAL();
385 CHECK_ARG(1,
int,krk_integer_type,howMany);
386 if (howMany < 0) howMany = 0;
388 size_t totalLength =
self->length * howMany;
389 char * out = malloc(totalLength + 1);
394 for (krk_integer_type i = 0; i < howMany; ++i) {
395 for (
size_t j = 0; j <
self->length; ++j) {
397 krk_hash_advance(hash, *c);
403 return OBJECT_VAL(
krk_takeStringVetted(out, totalLength, self->codesLength * howMany, (self->obj.flags & KRK_OBJ_FLAGS_STRING_MASK), hash));
406 KRK_Method(str,__rmul__) {
407 METHOD_TAKES_EXACTLY(1);
408 if (IS_INTEGER(argv[1]))
return FUNC_NAME(str,__mul__)(argc,argv,hasKw);
409 return NOTIMPL_VAL();
418 static int _str_join_callback(
void * context,
const KrkValue * values,
size_t count) {
421 for (
size_t i = 0; i < count; ++i) {
422 if (!IS_STRING(values[i])) {
424 "join",
"str", values[i]);
428 if (_context->isFirst) {
429 _context->isFirst = 0;
431 pushStringBuilderStr(_context->sb, (
char*)_context->self->
chars, _context->self->
length);
433 pushStringBuilderStr(_context->sb, (
char*)AS_STRING(values[i])->chars, AS_STRING(values[i])->length);
440 KRK_Method(str,join) {
441 METHOD_TAKES_EXACTLY(1);
447 discardStringBuilder(&sb);
451 return finishStringBuilder(&sb);
454 static int isWhitespace(
char c) {
455 return (c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'\r');
458 static int substringMatch(
const char * haystack,
size_t haystackLen,
const char * needle,
size_t needleLength) {
459 if (haystackLen < needleLength)
return 0;
460 for (
size_t i = 0; i < needleLength; ++i) {
461 if (haystack[i] != needle[i])
return 0;
467 KRK_Method(str,__contains__) {
468 METHOD_TAKES_EXACTLY(1);
469 if (IS_NONE(argv[1]))
return BOOLEAN_VAL(0);
471 for (
size_t i = 0; i <
self->length; ++i) {
472 if (substringMatch(self->chars + i, self->length - i, needle->chars, needle->length)) {
473 return BOOLEAN_VAL(1);
476 return BOOLEAN_VAL(0);
479 static int charIn(uint32_t c,
KrkString * str) {
481 if (c == KRK_STRING_FAST(str,i))
return 1;
490 static KrkValue _string_strip_shared(
int argc,
const KrkValue argv[],
int which) {
491 KrkString * subset = AS_STRING(
vm.specialMethodNames[METHOD_STRSTRIP]);
493 if (IS_STRING(argv[1])) {
494 subset = AS_STRING(argv[1]);
496 return krk_runtimeError(
vm.exceptions->typeError,
"argument to %sstrip() should be a string",
497 (which == 0 ?
"" : (which == 1 ?
"l" :
"r")));
507 size_t end =
self->length;
509 int k =
self->codesLength - 1;
511 if (which < 2)
while (start < end && charIn((c = KRK_STRING_FAST(
self, j)), subset)) { j++; start += CODEPOINT_BYTES(c); }
512 if (which != 1)
while (end > start && charIn((c = KRK_STRING_FAST(
self, k)), subset)) { k--; end -= CODEPOINT_BYTES(c); }
514 return OBJECT_VAL(
krk_copyString(&self->chars[start], end-start));
517 KRK_Method(str,strip) {
518 METHOD_TAKES_AT_MOST(1);
519 return _string_strip_shared(argc,argv,0);
521 KRK_Method(str,lstrip) {
522 METHOD_TAKES_AT_MOST(1);
523 return _string_strip_shared(argc,argv,1);
525 KRK_Method(str,rstrip) {
526 METHOD_TAKES_AT_MOST(1);
527 return _string_strip_shared(argc,argv,2);
530 #define strCompare(name,lop,iop,rop) \
531 KRK_Method(str,name) { \
532 METHOD_TAKES_EXACTLY(1); \
533 if (!IS_STRING(argv[1])) { \
534 return NOTIMPL_VAL(); \
536 size_t aLen = AS_STRING(argv[0])->length; \
537 size_t bLen = AS_STRING(argv[1])->length; \
538 const char * a = AS_CSTRING(argv[0]); \
539 const char * b = AS_CSTRING(argv[1]); \
540 for (size_t i = 0; i < ((aLen < bLen) ? aLen : bLen); i++) { \
541 if (a[i] lop b[i]) return BOOLEAN_VAL(1); \
542 if (a[i] iop b[i]) return BOOLEAN_VAL(0); \
544 return BOOLEAN_VAL((aLen rop bLen)); \
547 strCompare(__gt__,>,<,>)
548 strCompare(__lt__,<,>,<)
549 strCompare(__ge__,>,<,>=)
550 strCompare(__le__,<,>,<=)
552 KRK_Method(str,__mod__) {
553 METHOD_TAKES_EXACTLY(1);
557 if (IS_TUPLE(argv[1])) {
558 myTuple = AS_TUPLE(argv[1]);
569 for (
size_t i = 0; i <
self->length; ++i) {
570 if (self->chars[i] ==
'%') {
575 if (self->chars[i] ==
'%') {
576 pushStringBuilder(&sb, self->chars[i]);
580 if (self->chars[i] ==
'-') { backwards = 1; i++; }
582 while (self->chars[i] >=
'0' && self->chars[i] <=
'9') {
583 width = width * 10 + (
self->chars[i] -
'0');
587 if (self->chars[i] ==
'i') {
591 if (IS_INTEGER(arg)) {
592 krk_push(INTEGER_VAL(AS_INTEGER(arg)));
594 }
else if (IS_FLOATING(arg)) {
595 krk_push(INTEGER_VAL(AS_FLOATING(arg)));
598 krk_runtimeError(
vm.exceptions->typeError,
"%%i format: a number is required, not '%T'", arg);
603 }
else if (self->chars[i] ==
's') {
607 krk_runtimeError(
vm.exceptions->typeError,
"%%s format: cannot convert '%T' to string", arg);
615 krk_runtimeError(
vm.exceptions->typeError,
"%%%c format string specifier unsupported",
621 if (!backwards && width > AS_STRING(
krk_peek(0))->codesLength) {
622 while (width > AS_STRING(
krk_peek(0))->codesLength) {
623 pushStringBuilder(&sb,
' ');
628 pushStringBuilderStr(&sb, AS_CSTRING(
krk_peek(0)), AS_STRING(
krk_peek(0))->length);
629 if (backwards && width > AS_STRING(
krk_peek(0))->codesLength) {
630 while (width > AS_STRING(
krk_peek(0))->codesLength) {
631 pushStringBuilder(&sb,
' ');
637 pushStringBuilder(&sb, self->chars[i]);
642 krk_runtimeError(
vm.exceptions->typeError,
"not all arguments converted durin string formatting");
647 return finishStringBuilder(&sb);
654 discardStringBuilder(&sb);
659 KRK_Method(str,split) {
660 const char * sep = NULL;
665 ".|z#i", (
const char *[]){
"sep",
"maxsplit"},
671 if (sep && sepLen == 0)
return krk_runtimeError(
vm.exceptions->valueError,
"Empty separator");
677 char * c =
self->chars;
681 while (i != self->length) {
682 while (i != self->length && isWhitespace(*c)) {
686 if (i == self->length)
break;
688 if (count == maxsplit) {
696 while (i != self->length && !isWhitespace(*c)) {
697 pushStringBuilder(&sb, *c);
713 while (i != self->length) {
715 while (i != self->length && !substringMatch(c, self->length - i, sep, sepLen)) {
716 pushStringBuilder(&sb, *c);
723 if (i == self->length)
break;
727 if (count == maxsplit || i == self->length) {
739 KRK_Method(str,replace) {
740 METHOD_TAKES_AT_LEAST(2);
741 METHOD_TAKES_AT_MOST(3);
744 KrkValue count = (argc > 3 && IS_INTEGER(argv[3])) ? argv[3] : NONE_VAL();
748 int replacements = 0;
750 char * c =
self->chars;
751 while (i < self->length) {
752 if ( substringMatch(c, self->length - i, oldStr->chars, oldStr->length) && (IS_NONE(count) || replacements < AS_INTEGER(count))) {
753 pushStringBuilderStr(&sb, newStr->chars, newStr->length);
754 if (oldStr->length == 0) {
755 pushStringBuilder(&sb, *c);
763 pushStringBuilder(&sb, *c);
769 return finishStringBuilder(&sb);
772 #define WRAP_INDEX(index) \
773 if (index < 0) index += self->codesLength; \
774 if (index < 0) index = 0; \
775 if (index >= (krk_integer_type)self->codesLength) index = self->codesLength
777 KRK_Method(str,find) {
778 METHOD_TAKES_AT_LEAST(1);
779 METHOD_TAKES_AT_MOST(3);
782 krk_integer_type start = 0;
783 krk_integer_type end =
self->codesLength;
786 if (IS_INTEGER(argv[2])) {
787 start = AS_INTEGER(argv[2]);
789 return TYPE_ERROR(
int,argv[2]);
794 if (IS_INTEGER(argv[3])) {
795 end = AS_INTEGER(argv[3]);
797 return TYPE_ERROR(
int,argv[3]);
808 for (krk_integer_type i = start; i < end; ++i) {
810 for (j = 0; j < (krk_integer_type)substr->codesLength && (i + j < end); ++j) {
811 if (KRK_STRING_FAST(
self,i+j) != KRK_STRING_FAST(substr,j))
break;
813 if (j == (krk_integer_type)substr->codesLength)
return INTEGER_VAL(i);
816 return INTEGER_VAL(-1);
819 KRK_Method(str,index) {
820 KrkValue result = FUNC_NAME(str,find)(argc,argv,hasKw);
821 if (IS_INTEGER(result) && AS_INTEGER(result) == -1) {
827 KRK_Method(str,startswith) {
831 if (!
krk_parseArgs(
".O!|ii",(
const char*[]){
"prefix",
"start",
"end"}, KRK_BASE_CLASS(str), &substr, &start, &end)) {
841 if (end < start || (
size_t)(end - start) < substr->
codesLength)
return BOOLEAN_VAL(0);
844 if (KRK_STRING_FAST(
self, start + i) != KRK_STRING_FAST(substr,i))
return BOOLEAN_VAL(0);
846 return BOOLEAN_VAL(1);
849 KRK_Method(str,endswith) {
853 if (!
krk_parseArgs(
".O!|ii",(
const char*[]){
"suffix",
"start",
"end"}, KRK_BASE_CLASS(str), &substr, &start, &end)) {
863 if (end < start || (
size_t)(end - start) < substr->
codesLength)
return BOOLEAN_VAL(0);
866 if (KRK_STRING_FAST(
self, (end - i - 1)) != KRK_STRING_FAST(substr,(substr->
codesLength - i - 1)))
return BOOLEAN_VAL(0);
868 return BOOLEAN_VAL(1);
877 KRK_Method(str,__repr__) {
880 char * end = AS_CSTRING(argv[0]) + AS_STRING(argv[0])->length;
885 for (
char * c = AS_CSTRING(argv[0]); c < end; ++c) {
886 if (*c ==
'\'') singles++;
887 if (*c ==
'\"') doubles++;
890 char quote = (singles > doubles) ?
'\"' :
'\'';
892 pushStringBuilder(&sb, quote);
894 for (
char * c = AS_CSTRING(argv[0]); c < end; ++c) {
895 unsigned char ch = *c;
899 case '\'': addSlash = (quote == ch); ch =
'\'';
break;
900 case '\"': addSlash = (quote == ch); ch =
'\"';
break;
901 case '\\': addSlash = 1; ch =
'\\';
break;
902 case '\a': addSlash = 1; ch =
'a';
break;
903 case '\b': addSlash = 1; ch =
'b';
break;
904 case '\f': addSlash = 1; ch =
'f';
break;
905 case '\n': addSlash = 1; ch =
'n';
break;
906 case '\r': addSlash = 1; ch =
'r';
break;
907 case '\t': addSlash = 1; ch =
't';
break;
908 case '\v': addSlash = 1; ch =
'v';
break;
909 case 27: addSlash = 1; ch =
'[';
break;
911 if (ch <
' ' || ch == 0x7F) {
912 pushStringBuilder(&sb,
'\\');
913 pushStringBuilder(&sb,
'x');
915 snprintf(hex, 3,
"%02x", (
unsigned char)*c);
916 pushStringBuilder(&sb,hex[0]);
917 pushStringBuilder(&sb,hex[1]);
926 pushStringBuilder(&sb, quote);
928 return finishStringBuilder(&sb);
931 KRK_Method(str,encode) {
933 return OBJECT_VAL(
krk_newBytes(AS_STRING(argv[0])->length, (uint8_t*)AS_CSTRING(argv[0])));
936 KRK_Method(str,__str__) {
947 KRK_Method(str,__iter__) {
955 return OBJECT_VAL(output);
958 #define CHECK_ALL(test) do { \
959 krk_unicodeString(self); \
960 for (size_t i = 0; i < self->codesLength; ++i) { \
961 uint32_t c = KRK_STRING_FAST(self,i); \
962 if (!(test)) { return BOOLEAN_VAL(0); } \
963 } return BOOLEAN_VAL(1); } while (0)
965 KRK_Method(str,isalnum) {
966 CHECK_ALL( (c >=
'A' && c <=
'Z') || (c >=
'a' && c <=
'z') || (c >=
'0' && c <=
'9') );
969 KRK_Method(str,isalpha) {
970 CHECK_ALL( (c >=
'A' && c <=
'Z') || (c >=
'a' && c <=
'z') );
973 KRK_Method(str,isdigit) {
974 CHECK_ALL( (c >=
'0' && c <=
'9') );
977 KRK_Method(str,isxdigit) {
978 CHECK_ALL( (c >=
'A' && c <=
'F') || (c >=
'a' && c <=
'f') || (c >=
'0' && c <=
'9') );
981 KRK_Method(str,isspace) {
982 CHECK_ALL( (c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'\r' || c ==
'\v') );
985 KRK_Method(str,islower) {
986 CHECK_ALL( (c >=
'a' && c <=
'z') );
989 KRK_Method(str,isupper) {
990 CHECK_ALL( (c >=
'A' && c <=
'Z') );
993 KRK_Method(str,lower) {
997 for (
size_t i = 0; i <
self->length; ++i) {
998 if (self->chars[i] >=
'A' && self->chars[i] <=
'Z') {
999 pushStringBuilder(&sb, self->chars[i] + (
'a' -
'A'));
1001 pushStringBuilder(&sb, self->chars[i]);
1005 return finishStringBuilder(&sb);
1008 KRK_Method(str,upper) {
1009 METHOD_TAKES_NONE();
1012 for (
size_t i = 0; i <
self->length; ++i) {
1013 if (self->chars[i] >=
'a' && self->chars[i] <=
'z') {
1014 pushStringBuilder(&sb, self->chars[i] - (
'a' -
'A'));
1016 pushStringBuilder(&sb, self->chars[i]);
1020 return finishStringBuilder(&sb);
1023 KRK_Method(str,title) {
1024 METHOD_TAKES_NONE();
1027 int lastWasWhitespace = 1;
1029 for (
size_t i = 0; i <
self->length; ++i) {
1030 if (lastWasWhitespace && self->chars[i] >=
'a' && self->chars[i] <=
'z') {
1031 pushStringBuilder(&sb, self->chars[i] - (
'a' -
'A'));
1032 lastWasWhitespace = 0;
1033 }
else if (!lastWasWhitespace && self->chars[i] >=
'A' && self->chars[i] <=
'Z') {
1034 pushStringBuilder(&sb, self->chars[i] + (
'a' -
'A'));
1035 lastWasWhitespace = 0;
1037 pushStringBuilder(&sb, self->chars[i]);
1038 lastWasWhitespace = !((
self->chars[i] >=
'A' &&
self->chars[i] <=
'Z') || (self->chars[i] >=
'a' && self->chars[i] <=
'z'));
1042 return finishStringBuilder(&sb);
1045 #undef CURRENT_CTYPE
1046 #define CURRENT_CTYPE KrkInstance *
1047 KRK_Method(striterator,__init__) {
1048 METHOD_TAKES_EXACTLY(1);
1057 KRK_Method(striterator,__call__) {
1058 METHOD_TAKES_NONE();
1061 const char * errorStr = NULL;
1062 if (!
krk_tableGet(&self->fields, OBJECT_VAL(S(
"s")), &_str) || !IS_STRING(_str)) {
1063 errorStr =
"no str pointer";
1066 if (!
krk_tableGet(&self->fields, OBJECT_VAL(S(
"i")), &_counter) || !IS_INTEGER(_counter)) {
1067 errorStr =
"no index";
1071 if ((
size_t)AS_INTEGER(_counter) >= AS_STRING(_str)->codesLength) {
1075 return FUNC_NAME(str,__getitem__)(2,(
KrkValue[]){_str,_counter},3);
1078 return krk_runtimeError(
vm.exceptions->typeError,
"Corrupt str iterator: %s", errorStr);
1083 if (sb->capacity < sb->length + 1) {
1084 size_t old = sb->capacity;
1085 sb->capacity = KRK_GROW_CAPACITY(old);
1086 sb->bytes = KRK_GROW_ARRAY(
char, sb->bytes, old, sb->capacity);
1088 sb->bytes[sb->length++] = c;
1092 if (sb->capacity < sb->length + len) {
1093 size_t prevcap = sb->capacity;
1094 while (sb->capacity < sb->length + len) {
1095 size_t old = sb->capacity;
1096 sb->capacity = KRK_GROW_CAPACITY(old);
1098 sb->bytes = KRK_GROW_ARRAY(
char, sb->bytes, prevcap, sb->capacity);
1100 for (
size_t i = 0; i < len; ++i) {
1101 sb->bytes[sb->length++] = *(str++);
1106 KRK_FREE_ARRAY(
char,sb->bytes, sb->capacity);
1113 _freeStringBuilder(sb);
1119 _freeStringBuilder(sb);
1124 _freeStringBuilder(sb);
1128 int krk_pushStringBuilderFormatV(
struct StringBuilder * sb,
const char * fmt, va_list args) {
1129 for (
const char * f = fmt; *f; ++f) {
1131 pushStringBuilder(sb, *f);
1143 if (*f ==
'z') size = *f++;
1144 else if (*f ==
'l') size = *f++;
1145 else if (*f ==
'L') size = *f++;
1149 len = va_arg(args,
int);
1157 pushStringBuilder(sb,
'%');
1161 char val = (char)va_arg(args,
int);
1162 pushStringBuilder(sb, val);
1167 const char * c = va_arg(args,
const char *);
1168 pushStringBuilderStr(sb, c, len == -1 ? strlen(c) : (
size_t)len);
1175 val = va_arg(args,
unsigned int);
1176 }
else if (size ==
'l') {
1177 val = va_arg(args,
unsigned long);
1178 }
else if (size ==
'L') {
1179 val = va_arg(args,
unsigned long long);
1180 }
else if (size ==
'z') {
1181 val = va_arg(args,
size_t);
1184 snprintf(tmp, 32,
"%zu", val);
1185 pushStringBuilderStr(sb, tmp, strlen(tmp));
1192 val = va_arg(args,
int);
1193 }
else if (size ==
'l') {
1194 val = va_arg(args,
long);
1195 }
else if (size ==
'L') {
1196 val = va_arg(args,
long long);
1197 }
else if (size ==
'z') {
1198 val = va_arg(args, ssize_t);
1201 snprintf(tmp, 32,
"%zd", val);
1202 pushStringBuilderStr(sb, tmp, strlen(tmp));
1209 pushStringBuilderStr(sb, typeName, strlen(typeName));
1215 pushStringBuilderStr(sb, val->
chars, val->
length);
1222 if (likely(type->
_reprer != NULL)) {
1226 if (IS_STRING(res)) {
1227 pushStringBuilderStr(sb, AS_CSTRING(res), AS_STRING(res)->length);
1229 krk_runtimeError(
vm.exceptions->typeError,
"__repr__ returned non-string (type %T)", res);
1237 uintptr_t val = va_arg(args, uintptr_t);
1239 snprintf(tmp, 32,
"0x%zx", (
size_t)val);
1240 pushStringBuilderStr(sb, tmp, strlen(tmp));
1245 va_arg(args,
void*);
1246 pushStringBuilderStr(sb,
"(unsupported: ", 14);
1247 pushStringBuilder(sb, *f);
1248 pushStringBuilder(sb,
')');
1258 int krk_pushStringBuilderFormat(
struct StringBuilder * sb,
const char * fmt, ...) {
1260 va_start(args, fmt);
1261 int result = krk_pushStringBuilderFormatV(sb,fmt,args);
1266 KrkValue krk_stringFromFormat(
const char * fmt, ...) {
1269 va_start(args, fmt);
1270 int result = krk_pushStringBuilderFormatV(&sb,fmt,args);
1277 void _createAndBind_strClass(
void) {
1278 KrkClass * str = ADD_BASE_CLASS(
vm.baseClasses->strClass,
"str",
vm.baseClasses->objectClass);
1279 str->
obj.
flags |= KRK_OBJ_FLAGS_NO_INHERIT;
1281 BIND_STATICMETHOD(str,__new__);
1282 BIND_METHOD(str,__iter__);
1283 BIND_METHOD(str,__ord__);
1284 BIND_METHOD(str,__int__);
1285 BIND_METHOD(str,__float__);
1286 BIND_METHOD(str,__getitem__);
1287 BIND_METHOD(str,__setitem__);
1288 BIND_METHOD(str,__add__);
1289 BIND_METHOD(str,__len__);
1290 BIND_METHOD(str,__mul__);
1291 BIND_METHOD(str,__rmul__);
1292 BIND_METHOD(str,__contains__);
1293 BIND_METHOD(str,__lt__);
1294 BIND_METHOD(str,__gt__);
1295 BIND_METHOD(str,__le__);
1296 BIND_METHOD(str,__ge__);
1297 BIND_METHOD(str,__mod__);
1298 BIND_METHOD(str,__repr__);
1299 BIND_METHOD(str,__str__);
1300 BIND_METHOD(str,__hash__);
1301 BIND_METHOD(str,__format__);
1302 BIND_METHOD(str,encode);
1303 BIND_METHOD(str,split);
1304 BIND_METHOD(str,strip);
1305 BIND_METHOD(str,lstrip);
1306 BIND_METHOD(str,rstrip);
1307 BIND_METHOD(str,join);
1308 BIND_METHOD(str,format);
1309 BIND_METHOD(str,replace);
1310 BIND_METHOD(str,find);
1311 BIND_METHOD(str,index);
1312 BIND_METHOD(str,startswith);
1313 BIND_METHOD(str,endswith);
1316 BIND_METHOD(str,isalnum);
1317 BIND_METHOD(str,isalpha);
1318 BIND_METHOD(str,isdigit);
1319 BIND_METHOD(str,isxdigit);
1320 BIND_METHOD(str,isspace);
1321 BIND_METHOD(str,islower);
1322 BIND_METHOD(str,isupper);
1325 BIND_METHOD(str,lower);
1326 BIND_METHOD(str,upper);
1327 BIND_METHOD(str,title);
1331 KRK_DOC(str,
"Obtain a string representation of an object.");
1333 KrkClass * striterator = ADD_BASE_CLASS(
vm.baseClasses->striteratorClass,
"striterator",
vm.baseClasses->objectClass);
1334 striterator->
obj.
flags |= KRK_OBJ_FLAGS_NO_INHERIT;
1335 BIND_METHOD(striterator,__init__);
1336 BIND_METHOD(striterator,__call__);
KrkValue krk_runtimeError(KrkClass *type, const char *fmt,...)
Produce and raise an exception with a formatted message.
Functions for dealing with garbage collection and memory allocation.
KrkValue krk_parse_float(const char *s, size_t l)
Parse a string into a float.
KrkStringType
String compact storage type.
KrkBytes * krk_newBytes(size_t length, uint8_t *source)
Create a new byte array.
KrkObj * _tostr
__str__ Called to produce a string from an instance
KrkObj * _reprer
__repr__ Called to create a reproducible string representation of an instance
size_t allocSize
Size to allocate when creating instances of this class.
KrkTable methods
General attributes table.
void krk_finalizeClass(KrkClass *_class)
Finalize a class by collecting pointers to core methods.
int krk_bindMethod(KrkClass *_class, KrkString *name)
Perform method binding on the stack.
KrkInstance * krk_newInstance(KrkClass *_class)
Create a new instance of the given class.
KrkValue krk_list_of(int argc, const KrkValue argv[], int hasKw)
Create a list object.
The most basic object type.
uint16_t flags
General object flags, mostly related to garbage collection.
Immutable sequence of Unicode codepoints.
uint32_t krk_unicodeCodepoint(KrkString *string, size_t index)
Obtain the codepoint at a given index in a string.
void * krk_unicodeString(KrkString *string)
Ensure that a codepoint representation of a string is available.
KrkString * krk_copyString(const char *chars, size_t length)
Obtain a string object representation of the given C string.
size_t codesLength
String length in Unicode codepoints.
char * chars
UTF8 canonical data.
size_t length
String length in bytes.
KrkString * krk_takeStringVetted(char *chars, size_t length, size_t codesLength, KrkStringType type, uint32_t hash)
Like krk_takeString but for when the caller has already calculated code lengths, hash,...
size_t krk_codepointToBytes(krk_integer_type value, unsigned char *out)
Convert an integer codepoint to a UTF-8 byte representation.
int krk_tableGet(KrkTable *table, KrkValue key, KrkValue *value)
Obtain the value associated with a key in a table.
void krk_attachNamedObject(KrkTable *table, const char name[], KrkObj *obj)
Attach an object to an attribute table.
KrkNative * krk_defineNative(KrkTable *table, const char *name, NativeFn function)
Attach a native C function to an attribute table.
void krk_attachNamedValue(KrkTable *table, const char name[], KrkValue obj)
Attach a value to an attribute table.
Immutable sequence of arbitrary values.
KrkValueArray values
Stores the length, capacity, and actual values of the tuple.
KrkTuple * krk_newTuple(size_t length)
Create a new tuple.
void krk_writeValueArray(KrkValueArray *array, KrkValue value)
Add a value to a value array.
Stack reference or primative value.
const char * krk_typeName(KrkValue value)
Get the name of the type of a value.
KrkClass * krk_getType(KrkValue value)
Get the class representing a value.
Inline flexible string array.
Utilities for creating native bindings.
void krk_pushStringBuilderStr(struct StringBuilder *sb, const char *str, size_t len)
Append a string to the end of a string builder.
#define krk_parseArgs(f, n,...)
Parse arguments to a function while accepting keyword arguments.
KrkValue krk_finishStringBuilderBytes(struct StringBuilder *sb)
Finalize a string builder in a bytes object.
KrkValue krk_discardStringBuilder(struct StringBuilder *sb)
Discard the contents of a string builder.
int krk_unpackIterable(KrkValue iterable, void *context, int callback(void *, const KrkValue *, size_t))
Unpack an iterable.
KrkValue krk_finishStringBuilder(struct StringBuilder *sb)
Finalize a string builder into a string object.
void krk_pushStringBuilder(struct StringBuilder *sb, char c)
Add a character to the end of a string builder.
#define KRK_DOC(thing, text)
Attach documentation to a thing of various types.
Definitions for primitive stack references.
Core API for the bytecode virtual machine.
krk_threadLocal KrkThreadState krk_currentThread
Thread-local VM state.
KrkValue krk_callStack(int argCount)
Call a callable on the stack with argCount arguments.
#define vm
Convenience macro for namespacing.
KrkValue krk_pop(void)
Pop the top of the stack.
void krk_addObjects(void)
Concatenate two strings.
void krk_push(KrkValue value)
Push a stack value.
KrkValue krk_callDirect(KrkObj *callable, int argCount)
Call a closure or native function with argCount arguments.
KrkValue krk_peek(int distance)
Peek down from the top of the stack.