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 = 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 FLOATING_VAL(strtod(AS_CSTRING(argv[0]),NULL));
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) {
828 METHOD_TAKES_EXACTLY(1);
830 return BOOLEAN_VAL(substringMatch(self->chars,self->length,prefix->chars,prefix->length));
833 KRK_Method(str,endswith) {
834 METHOD_TAKES_EXACTLY(1);
836 if (suffix->length > self->length)
return BOOLEAN_VAL(0);
837 return BOOLEAN_VAL(substringMatch(self->chars + (self->length - suffix->length),
838 suffix->length, suffix->chars, suffix->length));
847 KRK_Method(str,__repr__) {
850 char * end = AS_CSTRING(argv[0]) + AS_STRING(argv[0])->length;
855 for (
char * c = AS_CSTRING(argv[0]); c < end; ++c) {
856 if (*c ==
'\'') singles++;
857 if (*c ==
'\"') doubles++;
860 char quote = (singles > doubles) ?
'\"' :
'\'';
862 pushStringBuilder(&sb, quote);
864 for (
char * c = AS_CSTRING(argv[0]); c < end; ++c) {
867 case '\\': pushStringBuilder(&sb,
'\\'); pushStringBuilder(&sb,
'\\');
break;
868 case '\'':
if (quote == *c) { pushStringBuilder(&sb,
'\\'); } pushStringBuilder(&sb,
'\'');
break;
869 case '\"':
if (quote == *c) { pushStringBuilder(&sb,
'\\'); } pushStringBuilder(&sb,
'\"');
break;
870 case '\a': pushStringBuilder(&sb,
'\\'); pushStringBuilder(&sb,
'a');
break;
871 case '\b': pushStringBuilder(&sb,
'\\'); pushStringBuilder(&sb,
'b');
break;
872 case '\f': pushStringBuilder(&sb,
'\\'); pushStringBuilder(&sb,
'f');
break;
873 case '\n': pushStringBuilder(&sb,
'\\'); pushStringBuilder(&sb,
'n');
break;
874 case '\r': pushStringBuilder(&sb,
'\\'); pushStringBuilder(&sb,
'r');
break;
875 case '\t': pushStringBuilder(&sb,
'\\'); pushStringBuilder(&sb,
't');
break;
876 case '\v': pushStringBuilder(&sb,
'\\'); pushStringBuilder(&sb,
'v');
break;
877 case 27: pushStringBuilder(&sb,
'\\'); pushStringBuilder(&sb,
'[');
break;
879 if ((
unsigned char)*c <
' ' || (
unsigned char)*c == 0x7F) {
880 pushStringBuilder(&sb,
'\\');
881 pushStringBuilder(&sb,
'x');
883 snprintf(hex, 3,
"%02x", (
unsigned char)*c);
884 pushStringBuilder(&sb,hex[0]);
885 pushStringBuilder(&sb,hex[1]);
887 pushStringBuilder(&sb,*c);
894 pushStringBuilder(&sb, quote);
896 return finishStringBuilder(&sb);
899 KRK_Method(str,encode) {
901 return OBJECT_VAL(
krk_newBytes(AS_STRING(argv[0])->length, (uint8_t*)AS_CSTRING(argv[0])));
904 KRK_Method(str,__str__) {
915 KRK_Method(str,__iter__) {
923 return OBJECT_VAL(output);
926 #define CHECK_ALL(test) do { \
927 krk_unicodeString(self); \
928 for (size_t i = 0; i < self->codesLength; ++i) { \
929 uint32_t c = KRK_STRING_FAST(self,i); \
930 if (!(test)) { return BOOLEAN_VAL(0); } \
931 } return BOOLEAN_VAL(1); } while (0)
933 KRK_Method(str,isalnum) {
934 CHECK_ALL( (c >=
'A' && c <=
'Z') || (c >=
'a' && c <=
'z') || (c >=
'0' && c <=
'9') );
937 KRK_Method(str,isalpha) {
938 CHECK_ALL( (c >=
'A' && c <=
'Z') || (c >=
'a' && c <=
'z') );
941 KRK_Method(str,isdigit) {
942 CHECK_ALL( (c >=
'0' && c <=
'9') );
945 KRK_Method(str,isxdigit) {
946 CHECK_ALL( (c >=
'A' && c <=
'F') || (c >=
'a' && c <=
'f') || (c >=
'0' && c <=
'9') );
949 KRK_Method(str,isspace) {
950 CHECK_ALL( (c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'\r' || c ==
'\v') );
953 KRK_Method(str,islower) {
954 CHECK_ALL( (c >=
'a' && c <=
'z') );
957 KRK_Method(str,isupper) {
958 CHECK_ALL( (c >=
'A' && c <=
'Z') );
961 KRK_Method(str,lower) {
965 for (
size_t i = 0; i <
self->length; ++i) {
966 if (self->chars[i] >=
'A' && self->chars[i] <=
'Z') {
967 pushStringBuilder(&sb, self->chars[i] + (
'a' -
'A'));
969 pushStringBuilder(&sb, self->chars[i]);
973 return finishStringBuilder(&sb);
976 KRK_Method(str,upper) {
980 for (
size_t i = 0; i <
self->length; ++i) {
981 if (self->chars[i] >=
'a' && self->chars[i] <=
'z') {
982 pushStringBuilder(&sb, self->chars[i] - (
'a' -
'A'));
984 pushStringBuilder(&sb, self->chars[i]);
988 return finishStringBuilder(&sb);
991 KRK_Method(str,title) {
995 int lastWasWhitespace = 1;
997 for (
size_t i = 0; i <
self->length; ++i) {
998 if (lastWasWhitespace && self->chars[i] >=
'a' && self->chars[i] <=
'z') {
999 pushStringBuilder(&sb, self->chars[i] - (
'a' -
'A'));
1000 lastWasWhitespace = 0;
1001 }
else if (!lastWasWhitespace && self->chars[i] >=
'A' && self->chars[i] <=
'Z') {
1002 pushStringBuilder(&sb, self->chars[i] + (
'a' -
'A'));
1003 lastWasWhitespace = 0;
1005 pushStringBuilder(&sb, self->chars[i]);
1006 lastWasWhitespace = !((
self->chars[i] >=
'A' &&
self->chars[i] <=
'Z') || (self->chars[i] >=
'a' && self->chars[i] <=
'z'));
1010 return finishStringBuilder(&sb);
1013 #undef CURRENT_CTYPE
1014 #define CURRENT_CTYPE KrkInstance *
1015 KRK_Method(striterator,__init__) {
1016 METHOD_TAKES_EXACTLY(1);
1025 KRK_Method(striterator,__call__) {
1026 METHOD_TAKES_NONE();
1029 const char * errorStr = NULL;
1030 if (!
krk_tableGet(&self->fields, OBJECT_VAL(S(
"s")), &_str) || !IS_STRING(_str)) {
1031 errorStr =
"no str pointer";
1034 if (!
krk_tableGet(&self->fields, OBJECT_VAL(S(
"i")), &_counter) || !IS_INTEGER(_counter)) {
1035 errorStr =
"no index";
1039 if ((
size_t)AS_INTEGER(_counter) >= AS_STRING(_str)->codesLength) {
1043 return FUNC_NAME(str,__getitem__)(2,(
KrkValue[]){_str,_counter},3);
1046 return krk_runtimeError(
vm.exceptions->typeError,
"Corrupt str iterator: %s", errorStr);
1051 if (sb->capacity < sb->length + 1) {
1052 size_t old = sb->capacity;
1053 sb->capacity = GROW_CAPACITY(old);
1054 sb->bytes = GROW_ARRAY(
char, sb->bytes, old, sb->capacity);
1056 sb->bytes[sb->length++] = c;
1060 if (sb->capacity < sb->length + len) {
1061 size_t prevcap = sb->capacity;
1062 while (sb->capacity < sb->length + len) {
1063 size_t old = sb->capacity;
1064 sb->capacity = GROW_CAPACITY(old);
1066 sb->bytes = GROW_ARRAY(
char, sb->bytes, prevcap, sb->capacity);
1068 for (
size_t i = 0; i < len; ++i) {
1069 sb->bytes[sb->length++] = *(str++);
1074 FREE_ARRAY(
char,sb->bytes, sb->capacity);
1081 _freeStringBuilder(sb);
1087 _freeStringBuilder(sb);
1092 _freeStringBuilder(sb);
1096 int krk_pushStringBuilderFormatV(
struct StringBuilder * sb,
const char * fmt, va_list args) {
1097 for (
const char * f = fmt; *f; ++f) {
1099 pushStringBuilder(sb, *f);
1113 if (*f ==
'z') size = *f++;
1114 else if (*f ==
'l') size = *f++;
1115 else if (*f ==
'L') size = *f++;
1119 len = va_arg(args,
int);
1127 pushStringBuilder(sb,
'%');
1131 char val = (char)va_arg(args,
int);
1132 pushStringBuilder(sb, val);
1137 const char * c = va_arg(args,
const char *);
1138 pushStringBuilderStr(sb, c, len == -1 ? strlen(c) : (
size_t)len);
1145 val = va_arg(args,
unsigned int);
1146 }
else if (size ==
'l') {
1147 val = va_arg(args,
unsigned long);
1148 }
else if (size ==
'L') {
1149 val = va_arg(args,
unsigned long long);
1150 }
else if (size ==
'z') {
1151 val = va_arg(args,
size_t);
1154 snprintf(tmp, 32,
"%zu", val);
1155 pushStringBuilderStr(sb, tmp, strlen(tmp));
1162 val = va_arg(args,
int);
1163 }
else if (size ==
'l') {
1164 val = va_arg(args,
long);
1165 }
else if (size ==
'L') {
1166 val = va_arg(args,
long long);
1167 }
else if (size ==
'z') {
1168 val = va_arg(args, ssize_t);
1171 snprintf(tmp, 32,
"%zd", val);
1172 pushStringBuilderStr(sb, tmp, strlen(tmp));
1179 pushStringBuilderStr(sb, typeName, strlen(typeName));
1185 pushStringBuilderStr(sb, val->
chars, val->
length);
1192 if (likely(type->
_reprer != NULL)) {
1196 if (IS_STRING(res)) {
1197 pushStringBuilderStr(sb, AS_CSTRING(res), AS_STRING(res)->length);
1205 uintptr_t val = va_arg(args, uintptr_t);
1207 snprintf(tmp, 32,
"0x%zx", (
size_t)val);
1208 pushStringBuilderStr(sb, tmp, strlen(tmp));
1213 va_arg(args,
void*);
1214 pushStringBuilderStr(sb,
"(unsupported: ", 14);
1215 pushStringBuilder(sb, *f);
1216 pushStringBuilder(sb,
')');
1225 int krk_pushStringBuilderFormat(
struct StringBuilder * sb,
const char * fmt, ...) {
1227 va_start(args, fmt);
1228 int result = krk_pushStringBuilderFormatV(sb,fmt,args);
1233 KrkValue krk_stringFromFormat(
const char * fmt, ...) {
1236 va_start(args, fmt);
1237 int result = krk_pushStringBuilderFormatV(&sb,fmt,args);
1244 void _createAndBind_strClass(
void) {
1245 KrkClass * str = ADD_BASE_CLASS(
vm.baseClasses->strClass,
"str",
vm.baseClasses->objectClass);
1246 str->
obj.
flags |= KRK_OBJ_FLAGS_NO_INHERIT;
1248 BIND_STATICMETHOD(str,__new__);
1249 BIND_METHOD(str,__iter__);
1250 BIND_METHOD(str,__ord__);
1251 BIND_METHOD(str,__int__);
1252 BIND_METHOD(str,__float__);
1253 BIND_METHOD(str,__getitem__);
1254 BIND_METHOD(str,__setitem__);
1255 BIND_METHOD(str,__add__);
1256 BIND_METHOD(str,__len__);
1257 BIND_METHOD(str,__mul__);
1258 BIND_METHOD(str,__rmul__);
1259 BIND_METHOD(str,__contains__);
1260 BIND_METHOD(str,__lt__);
1261 BIND_METHOD(str,__gt__);
1262 BIND_METHOD(str,__le__);
1263 BIND_METHOD(str,__ge__);
1264 BIND_METHOD(str,__mod__);
1265 BIND_METHOD(str,__repr__);
1266 BIND_METHOD(str,__str__);
1267 BIND_METHOD(str,__hash__);
1268 BIND_METHOD(str,__format__);
1269 BIND_METHOD(str,encode);
1270 BIND_METHOD(str,split);
1271 BIND_METHOD(str,strip);
1272 BIND_METHOD(str,lstrip);
1273 BIND_METHOD(str,rstrip);
1274 BIND_METHOD(str,join);
1275 BIND_METHOD(str,format);
1276 BIND_METHOD(str,replace);
1277 BIND_METHOD(str,find);
1278 BIND_METHOD(str,index);
1279 BIND_METHOD(str,startswith);
1280 BIND_METHOD(str,endswith);
1283 BIND_METHOD(str,isalnum);
1284 BIND_METHOD(str,isalpha);
1285 BIND_METHOD(str,isdigit);
1286 BIND_METHOD(str,isxdigit);
1287 BIND_METHOD(str,isspace);
1288 BIND_METHOD(str,islower);
1289 BIND_METHOD(str,isupper);
1292 BIND_METHOD(str,lower);
1293 BIND_METHOD(str,upper);
1294 BIND_METHOD(str,title);
1298 KRK_DOC(str,
"Obtain a string representation of an object.");
1300 KrkClass * striterator = ADD_BASE_CLASS(
vm.baseClasses->striteratorClass,
"striterator",
vm.baseClasses->objectClass);
1301 striterator->
obj.
flags |= KRK_OBJ_FLAGS_NO_INHERIT;
1302 BIND_METHOD(striterator,__init__);
1303 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.
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.
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.
threadLocal KrkThreadState krk_currentThread
Thread-local VM state.
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.