obj_str.c
1 #include <string.h>
2 #include <kuroko/vm.h>
3 #include <kuroko/value.h>
4 #include <kuroko/memory.h>
5 #include <kuroko/util.h>
6 
7 #include "private.h"
8 
9 static KrkValue FUNC_NAME(striterator,__init__)(int,const KrkValue[],int);
10 
11 #define CURRENT_CTYPE KrkString *
12 #define CURRENT_NAME self
13 
14 #define AT_END() (self->length == 0 || i == self->length - 1)
15 
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]))
20 
21 #define CODEPOINT_BYTES(cp) (cp < 0x80 ? 1 : (cp < 0x800 ? 2 : (cp < 0x10000 ? 3 : 4)))
22 
23 KRK_Method(str,__ord__) {
24  METHOD_TAKES_NONE();
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);
27  return INTEGER_VAL(krk_unicodeCodepoint(self,0));
28 }
29 
30 KRK_StaticMethod(str,__new__) {
31  /* Ignore argument which would have been an instance */
32  if (argc < 2) {
33  return OBJECT_VAL(S(""));
34  }
35  FUNCTION_TAKES_AT_MOST(2);
36  if (IS_STRING(argv[1])) return argv[1]; /* strings are immutable, so we can just return the arg */
37  /* Find the type of arg */
38  krk_push(argv[1]);
39  if (!krk_getType(argv[1])->_tostr) return krk_runtimeError(vm.exceptions->typeError, "Can not convert '%T' to str", argv[1]);
40  return krk_callDirect(krk_getType(argv[1])->_tostr, 1);
41 }
42 
43 KRK_Method(str,__add__) {
44  METHOD_TAKES_EXACTLY(1);
45  CHECK_ARG(1,str,KrkString*,them);
46  const char * a;
47  const char * b;
48  size_t al;
49  size_t bl;
50  int needsPop = 0;
51 
52  a = AS_CSTRING(argv[0]);
53  al = self->length;
54 
55  b = AS_CSTRING(argv[1]);
56  bl = them->length;
57 
58  size_t length = al + bl;
59  char * chars = KRK_ALLOCATE(char, length + 1);
60  memcpy(chars, a, al);
61  memcpy(chars + al, b, bl);
62  chars[length] = '\0';
63 
64  size_t cpLength = self->codesLength + them->codesLength;
65 
66  int self_type = (self->obj.flags & KRK_OBJ_FLAGS_STRING_MASK);
67  int them_type = (them->obj.flags & KRK_OBJ_FLAGS_STRING_MASK);
68 
69  KrkStringType type = self_type > them_type ? self_type : them_type;
70 
71  /* Hashes can be extended, which saves us calculating the whole thing */
72  uint32_t hash = self->obj.hash;
73  for (size_t i = 0; i < bl; ++i) {
74  krk_hash_advance(hash,b[i]);
75  }
76 
77  KrkString * result = krk_takeStringVetted(chars, length, cpLength, type, hash);
78  if (needsPop) krk_pop();
79  return OBJECT_VAL(result);
80 }
81 
82 KRK_Method(str,__hash__) {
83  return INTEGER_VAL(self->obj.hash);
84 }
85 
86 KRK_Method(str,__len__) {
87  return INTEGER_VAL(self->codesLength);
88 }
89 
90 KRK_Method(str,__setitem__) {
91  return krk_runtimeError(vm.exceptions->typeError, "Strings are not mutable.");
92 }
93 
94 /* str.__int__(base=10) */
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);
99 }
100 
101 /* str.__float__() */
102 KRK_Method(str,__float__) {
103  METHOD_TAKES_NONE();
104 #ifndef KRK_NO_FLOAT
105  return krk_parse_float(AS_CSTRING(argv[0]),AS_STRING(argv[0])->length);
106 #else
107  return krk_runtimeError(vm.exceptions->valueError, "no float support");
108 #endif
109 }
110 
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);
118  }
119  if ((self->obj.flags & KRK_OBJ_FLAGS_STRING_MASK) == KRK_OBJ_FLAGS_STRING_ASCII) {
120  return OBJECT_VAL(krk_copyString(self->chars + asInt, 1));
121  } else {
122  krk_unicodeString(self);
123  unsigned char asbytes[5];
124  size_t length = krk_codepointToBytes(KRK_STRING_FAST(self,asInt),(unsigned char*)&asbytes);
125  return OBJECT_VAL(krk_copyString((char*)&asbytes, length));
126  }
127  } else if (IS_slice(argv[1])) {
128  KRK_SLICER(argv[1], self->codesLength) {
129  return NONE_VAL();
130  }
131 
132  if (step == 1) {
133  long len = end - start;
134  if ((self->obj.flags & KRK_OBJ_FLAGS_STRING_MASK) == KRK_OBJ_FLAGS_STRING_ASCII) {
135  return OBJECT_VAL(krk_copyString(self->chars + start, len));
136  } else {
137  size_t offset = 0;
138  size_t length = 0;
139  /* Figure out where the UTF8 for this string starts. */
140  krk_unicodeString(self);
141  for (long i = 0; i < start; ++i) {
142  uint32_t cp = KRK_STRING_FAST(self,i);
143  offset += CODEPOINT_BYTES(cp);
144  }
145  for (long i = start; i < end; ++i) {
146  uint32_t cp = KRK_STRING_FAST(self,i);
147  length += CODEPOINT_BYTES(cp);
148  }
149  return OBJECT_VAL(krk_copyString(self->chars + offset, length));
150  }
151  } else {
152  struct StringBuilder sb = {0};
153  krk_unicodeString(self);
154 
155  unsigned char asbytes[5];
156  krk_integer_type i = start;
157 
158  while ((step < 0) ? (i > end) : (i < end)) {
159  size_t length = krk_codepointToBytes(KRK_STRING_FAST(self,i),(unsigned char*)&asbytes);
160  pushStringBuilderStr(&sb, (char*)asbytes, length);
161  i += step;
162  }
163 
164  return finishStringBuilder(&sb);
165  }
166  } else {
167  return TYPE_ERROR(int or slice, argv[1]);
168  }
169 }
170 
171 const char * krk_parseCommonFormatSpec(struct ParsedFormatSpec *result, const char * spec, size_t length);
172 
173 KRK_Method(str,__format__) {
174  METHOD_TAKES_EXACTLY(1);
175  CHECK_ARG(1,str,KrkString*,format_spec);
176 
177  struct ParsedFormatSpec opts = {0};
178  const char * spec = krk_parseCommonFormatSpec(&opts, format_spec->chars, format_spec->length);
179  if (!spec) return NONE_VAL();
180 
181  switch (*spec) {
182  case 0: /* unspecified */
183  case 's':
184  break;
185  default:
186  return krk_runtimeError(vm.exceptions->valueError,
187  "Unknown format code '%c' for object of type '%s'",
188  *spec,
189  "str");
190  }
191 
192  /* Note we're going to deal in codepoints exclusive here, so hold on to your hat. */
193  krk_unicodeString(self);
194 
195  size_t actualLength = self->codesLength;
196 
197  /* Restrict to the precision specified */
198  if (opts.hasPrecision && (size_t)opts.prec < actualLength) {
199  actualLength = opts.prec;
200  }
201 
202  /* How much padding do we need? */
203  size_t padLeft = 0;
204  size_t padRight = 0;
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;
213  }
214  }
215 
216  /* If there's no work to do, return self */
217  if (padLeft == 0 && padRight == 0 && actualLength == self->codesLength) {
218  return argv[0];
219  }
220 
221  struct StringBuilder sb = {0};
222 
223  /* Push left padding */
224  for (size_t i = 0; i < padLeft; ++i) {
225  pushStringBuilderStr(&sb, opts.fill, opts.fillSize);
226  }
227 
228  /* Push codes from us */
229  size_t offset = 0;
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);
234  offset += bytes;
235  }
236 
237  /* Push right padding */
238  for (size_t i = 0; i < padRight; ++i) {
239  pushStringBuilderStr(&sb, opts.fill, opts.fillSize);
240  }
241 
242  return finishStringBuilder(&sb);
243 }
244 
245 /* str.format(**kwargs) */
246 KRK_Method(str,format) {
247  KrkValue kwargs = NONE_VAL();
248  if (hasKw) {
249  kwargs = argv[argc];
250  }
251 
252  /* Read through `self` until we find a field specifier. */
253  struct StringBuilder sb = {0};
254 
255  int counterOffset = 0;
256  char * erroneousField = NULL;
257  int erroneousIndex = -1;
258  const char * errorStr = "";
259 
260  char * workSpace = strdup(self->chars);
261  char * c = workSpace;
262  for (size_t i = 0; i < self->length; i++, c++) {
263  if (*c == '{') {
264  if (!AT_END() && c[1] == '{') {
265  pushStringBuilder(&sb, '{');
266  i++; c++; /* Skip both */
267  continue;
268  } else {
269  /* Start field specifier */
270  i++; c++; /* Skip the { */
271  char * fieldStart = c;
272  char * fieldStop = NULL;
273  for (; i < self->length; i++, c++) {
274  if (*c == '}') {
275  fieldStop = c;
276  break;
277  }
278  }
279  if (!fieldStop) {
280  errorStr = "Unclosed { found.";
281  goto _formatError;
282  }
283  size_t fieldLength = fieldStop - fieldStart;
284  *fieldStop = '\0';
285  /* fieldStart is now a nice little C string... */
286  int isDigits = 1;
287  for (char * field = fieldStart; *field; ++field) {
288  if (!(*field >= '0' && *field <= '9')) {
289  isDigits = 0;
290  break;
291  }
292  }
293  KrkValue value;
294  if (isDigits) {
295  /* Must be positional */
296  int positionalOffset;
297  if (fieldLength == 0) {
298  positionalOffset = counterOffset++;
299  } else if (counterOffset) {
300  goto _formatSwitchedNumbering;
301  } else {
302  positionalOffset = strtoul(fieldStart,NULL,10);
303  }
304  if (positionalOffset >= argc - 1) {
305  erroneousIndex = positionalOffset;
306  goto _formatOutOfRange;
307  }
308  value = argv[1 + positionalOffset];
309  } else if (hasKw) {
310  KrkValue fieldAsString = OBJECT_VAL(krk_copyString(fieldStart, fieldLength));
311  krk_push(fieldAsString);
312  if (!krk_tableGet(AS_DICT(kwargs), fieldAsString, &value)) {
313  erroneousField = fieldStart;
314  goto _formatKeyError;
315  }
316  krk_pop(); /* fieldAsString */
317  } else {
318  erroneousField = fieldStart;
319  goto _formatKeyError;
320  }
321  KrkValue asString;
322  if (IS_STRING(value)) {
323  asString = value;
324  } else {
325  krk_push(value);
326  KrkClass * type = krk_getType(value);
327  if (type->_tostr) {
328  asString = krk_callDirect(type->_tostr, 1);
329  } else {
330  if (!krk_bindMethod(type, AS_STRING(vm.specialMethodNames[METHOD_STR]))) {
331  errorStr = "Failed to convert field to string.";
332  goto _formatError;
333  }
334  asString = krk_callStack(0);
335  }
336  if (!IS_STRING(asString)) goto _freeAndDone;
337  }
338  krk_push(asString);
339  pushStringBuilderStr(&sb, AS_CSTRING(asString), AS_STRING(asString)->length);
340  krk_pop();
341  }
342  } else if (*c == '}') {
343  if (!AT_END() && c[1] == '}') {
344  pushStringBuilder(&sb, '}');
345  i++; c++; /* Skip both */
346  continue;
347  } else {
348  errorStr = "Single } found.";
349  goto _formatError;
350  }
351  } else {
352  pushStringBuilder(&sb, *c);
353  }
354  }
355 
356  free(workSpace);
357  return finishStringBuilder(&sb);
358 
359 _formatError:
360  krk_runtimeError(vm.exceptions->typeError, "Error parsing format string: %s", errorStr);
361  goto _freeAndDone;
362 
363 _formatSwitchedNumbering:
364  krk_runtimeError(vm.exceptions->valueError, "Can not switch from automatic indexing to manual indexing");
365  goto _freeAndDone;
366 
367 _formatOutOfRange:
368  krk_runtimeError(vm.exceptions->indexError, "Positional index out of range: %d", erroneousIndex);
369  goto _freeAndDone;
370 
371 _formatKeyError:
372  /* which one? */
373  krk_runtimeError(vm.exceptions->keyError, "'%s'", erroneousField);
374  goto _freeAndDone;
375 
376 _freeAndDone:
377  discardStringBuilder(&sb);
378  free(workSpace);
379  return NONE_VAL();
380 }
381 
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;
387 
388  size_t totalLength = self->length * howMany;
389  char * out = malloc(totalLength + 1);
390  char * c = out;
391 
392  uint32_t hash = 0;
393 
394  for (krk_integer_type i = 0; i < howMany; ++i) {
395  for (size_t j = 0; j < self->length; ++j) {
396  *c = self->chars[j];
397  krk_hash_advance(hash, *c);
398  c++;
399  }
400  }
401 
402  *c = '\0';
403  return OBJECT_VAL(krk_takeStringVetted(out, totalLength, self->codesLength * howMany, (self->obj.flags & KRK_OBJ_FLAGS_STRING_MASK), hash));
404 }
405 
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();
410 }
411 
413  struct StringBuilder * sb;
414  KrkString * self;
415  int isFirst;
416 };
417 
418 static int _str_join_callback(void * context, const KrkValue * values, size_t count) {
419  struct _str_join_context * _context = context;
420 
421  for (size_t i = 0; i < count; ++i) {
422  if (!IS_STRING(values[i])) {
423  krk_runtimeError(vm.exceptions->typeError, "%s() expects %s, not '%T'",
424  "join", "str", values[i]);
425  return 1;
426  }
427 
428  if (_context->isFirst) {
429  _context->isFirst = 0;
430  } else {
431  pushStringBuilderStr(_context->sb, (char*)_context->self->chars, _context->self->length);
432  }
433  pushStringBuilderStr(_context->sb, (char*)AS_STRING(values[i])->chars, AS_STRING(values[i])->length);
434  }
435 
436  return 0;
437 }
438 
439 /* str.join(list) */
440 KRK_Method(str,join) {
441  METHOD_TAKES_EXACTLY(1);
442  struct StringBuilder sb = {0};
443 
444  struct _str_join_context context = {&sb, self, 1};
445 
446  if (krk_unpackIterable(argv[1], &context, _str_join_callback)) {
447  discardStringBuilder(&sb);
448  return NONE_VAL();
449  }
450 
451  return finishStringBuilder(&sb);
452 }
453 
454 static int isWhitespace(char c) {
455  return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
456 }
457 
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;
462  }
463  return 1;
464 }
465 
466 /* str.__contains__ */
467 KRK_Method(str,__contains__) {
468  METHOD_TAKES_EXACTLY(1);
469  if (IS_NONE(argv[1])) return BOOLEAN_VAL(0);
470  CHECK_ARG(1,str,KrkString*,needle);
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);
474  }
475  }
476  return BOOLEAN_VAL(0);
477 }
478 
479 static int charIn(uint32_t c, KrkString * str) {
480  for (size_t i = 0; i < str->codesLength; ++i) {
481  if (c == KRK_STRING_FAST(str,i)) return 1;
482  }
483  return 0;
484 }
485 
490 static KrkValue _string_strip_shared(int argc, const KrkValue argv[], int which) {
491  KrkString * subset = AS_STRING(vm.specialMethodNames[METHOD_STRSTRIP]);
492  if (argc > 1) {
493  if (IS_STRING(argv[1])) {
494  subset = AS_STRING(argv[1]);
495  } else {
496  return krk_runtimeError(vm.exceptions->typeError, "argument to %sstrip() should be a string",
497  (which == 0 ? "" : (which == 1 ? "l" : "r")));
498  }
499  }
500 
501  KrkString * self = AS_STRING(argv[0]);
502  krk_unicodeString(self);
503  krk_unicodeString(subset);
504 
505  uint32_t c;
506  size_t start = 0;
507  size_t end = self->length;
508  int j = 0;
509  int k = self->codesLength - 1;
510 
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); }
513 
514  return OBJECT_VAL(krk_copyString(&self->chars[start], end-start));
515 }
516 
517 KRK_Method(str,strip) {
518  METHOD_TAKES_AT_MOST(1); /* TODO */
519  return _string_strip_shared(argc,argv,0);
520 }
521 KRK_Method(str,lstrip) {
522  METHOD_TAKES_AT_MOST(1); /* TODO */
523  return _string_strip_shared(argc,argv,1);
524 }
525 KRK_Method(str,rstrip) {
526  METHOD_TAKES_AT_MOST(1); /* TODO */
527  return _string_strip_shared(argc,argv,2);
528 }
529 
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(); \
535  } \
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); \
543  } \
544  return BOOLEAN_VAL((aLen rop bLen)); \
545  }
546 
547 strCompare(__gt__,>,<,>)
548 strCompare(__lt__,<,>,<)
549 strCompare(__ge__,>,<,>=)
550 strCompare(__le__,<,>,<=)
551 
552 KRK_Method(str,__mod__) {
553  METHOD_TAKES_EXACTLY(1);
554 
555  KrkTuple * myTuple;
556 
557  if (IS_TUPLE(argv[1])) {
558  myTuple = AS_TUPLE(argv[1]);
559  krk_push(argv[1]);
560  } else {
561  myTuple = krk_newTuple(1);
562  krk_push(OBJECT_VAL(myTuple));
563  myTuple->values.values[myTuple->values.count++] = argv[1];
564  }
565 
566  struct StringBuilder sb = {0};
567  size_t ti = 0;
568 
569  for (size_t i = 0; i < self->length; ++i) {
570  if (self->chars[i] == '%') {
571  int backwards = 0;
572  size_t width = 0;
573  i++;
574 
575  if (self->chars[i] == '%') {
576  pushStringBuilder(&sb, self->chars[i]);
577  continue;
578  }
579 
580  if (self->chars[i] == '-') { backwards = 1; i++; }
581 
582  while (self->chars[i] >= '0' && self->chars[i] <= '9') {
583  width = width * 10 + (self->chars[i] - '0');
584  i++;
585  }
586 
587  if (self->chars[i] == 'i') {
588  if (ti >= myTuple->values.count) goto _notEnough;
589  KrkValue arg = myTuple->values.values[ti++];
590 
591  if (IS_INTEGER(arg)) {
592  krk_push(INTEGER_VAL(AS_INTEGER(arg)));
593 #ifndef KRK_NO_FLOAT
594  } else if (IS_FLOATING(arg)) {
595  krk_push(INTEGER_VAL(AS_FLOATING(arg)));
596 #endif
597  } else {
598  krk_runtimeError(vm.exceptions->typeError, "%%i format: a number is required, not '%T'", arg);
599  goto _exception;
600  }
601  krk_push(krk_callDirect(krk_getType(arg)->_tostr, 1));
602  goto _doit;
603  } else if (self->chars[i] == 's') {
604  if (ti >= myTuple->values.count) goto _notEnough;
605  KrkValue arg = myTuple->values.values[ti++];
606  if (!krk_getType(arg)->_tostr) {
607  krk_runtimeError(vm.exceptions->typeError, "%%s format: cannot convert '%T' to string", arg);
608  goto _exception;
609  }
610 
611  krk_push(arg);
612  krk_push(krk_callDirect(krk_getType(arg)->_tostr, 1));
613  goto _doit;
614  } else {
615  krk_runtimeError(vm.exceptions->typeError, "%%%c format string specifier unsupported",
616  self->chars[i]);
617  goto _exception;
618  }
619 
620 _doit:
621  if (!backwards && width > AS_STRING(krk_peek(0))->codesLength) {
622  while (width > AS_STRING(krk_peek(0))->codesLength) {
623  pushStringBuilder(&sb, ' ');
624  width--;
625  }
626  }
627 
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, ' ');
632  width--;
633  }
634  }
635  krk_pop();
636  } else {
637  pushStringBuilder(&sb, self->chars[i]);
638  }
639  }
640 
641  if (ti != myTuple->values.count) {
642  krk_runtimeError(vm.exceptions->typeError, "not all arguments converted durin string formatting");
643  goto _exception;
644  }
645 
646  krk_pop(); /* tuple */
647  return finishStringBuilder(&sb);
648 
649 _notEnough:
650  krk_runtimeError(vm.exceptions->typeError, "not enough arguments for string format");
651  goto _exception;
652 
653 _exception:
654  discardStringBuilder(&sb);
655  return NONE_VAL();
656 }
657 
658 /* str.split() */
659 KRK_Method(str,split) {
660  const char * sep = NULL;
661  size_t sepLen = 0;
662  int maxsplit = -1;
663 
664  if (!krk_parseArgs(
665  ".|z#i", (const char *[]){"sep","maxsplit"},
666  &sep, &sepLen,
667  &maxsplit)) {
668  return NONE_VAL();
669  }
670 
671  if (sep && sepLen == 0) return krk_runtimeError(vm.exceptions->valueError, "Empty separator");
672 
673  KrkValue myList = krk_list_of(0,NULL,0);
674  krk_push(myList);
675 
676  size_t i = 0;
677  char * c = self->chars;
678  ssize_t count = 0;
679 
680  if (!sep) {
681  while (i != self->length) {
682  while (i != self->length && isWhitespace(*c)) {
683  i++;
684  c++;
685  }
686  if (i == self->length) break;
687 
688  if (count == maxsplit) {
689  krk_push(OBJECT_VAL(krk_copyString(&self->chars[i], self->length - i)));
690  krk_writeValueArray(AS_LIST(myList), krk_peek(0));
691  krk_pop();
692  break;
693  }
694 
695  struct StringBuilder sb = {0};
696  while (i != self->length && !isWhitespace(*c)) {
697  pushStringBuilder(&sb, *c);
698  i++;
699  c++;
700  }
701  krk_push(finishStringBuilder(&sb));
702  krk_writeValueArray(AS_LIST(myList), krk_peek(0));
703  krk_pop();
704  count++;
705  }
706  } else {
707  /* Special case 0 */
708  if (maxsplit == 0) {
709  krk_writeValueArray(AS_LIST(myList), argv[0]);
710  return krk_pop();
711  }
712 
713  while (i != self->length) {
714  struct StringBuilder sb = {0};
715  while (i != self->length && !substringMatch(c, self->length - i, sep, sepLen)) {
716  pushStringBuilder(&sb, *c);
717  i++;
718  c++;
719  }
720  krk_push(finishStringBuilder(&sb));
721  krk_writeValueArray(AS_LIST(myList), krk_peek(0));
722  krk_pop();
723  if (i == self->length) break;
724  i += sepLen;
725  c += sepLen;
726  count++;
727  if (count == maxsplit || i == self->length) {
728  krk_push(OBJECT_VAL(krk_copyString(&self->chars[i], self->length - i)));
729  krk_writeValueArray(AS_LIST(myList), krk_peek(0));
730  krk_pop();
731  break;
732  }
733  }
734  }
735 
736  return krk_pop();
737 }
738 
739 KRK_Method(str,replace) {
740  METHOD_TAKES_AT_LEAST(2);
741  METHOD_TAKES_AT_MOST(3);
742  CHECK_ARG(1,str,KrkString*,oldStr);
743  CHECK_ARG(2,str,KrkString*,newStr);
744  KrkValue count = (argc > 3 && IS_INTEGER(argv[3])) ? argv[3] : NONE_VAL();
745 
746  struct StringBuilder sb = {0};
747 
748  int replacements = 0;
749  size_t i = 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);
756  c++;
757  i++;
758  }
759  c += oldStr->length;
760  i += oldStr->length;
761  replacements++;
762  } else {
763  pushStringBuilder(&sb, *c);
764  c++;
765  i++;
766  }
767  }
768 
769  return finishStringBuilder(&sb);
770 }
771 
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
776 
777 KRK_Method(str,find) {
778  METHOD_TAKES_AT_LEAST(1);
779  METHOD_TAKES_AT_MOST(3);
780  CHECK_ARG(1,str,KrkString*,substr);
781 
782  krk_integer_type start = 0;
783  krk_integer_type end = self->codesLength;
784 
785  if (argc > 2) {
786  if (IS_INTEGER(argv[2])) {
787  start = AS_INTEGER(argv[2]);
788  } else {
789  return TYPE_ERROR(int,argv[2]);
790  }
791  }
792 
793  if (argc > 3) {
794  if (IS_INTEGER(argv[3])) {
795  end = AS_INTEGER(argv[3]);
796  } else {
797  return TYPE_ERROR(int,argv[3]);
798  }
799  }
800 
801  WRAP_INDEX(start);
802  WRAP_INDEX(end);
803 
804  /* Make sure both strings have code representations */
805  krk_unicodeString(self);
806  krk_unicodeString(substr);
807 
808  for (krk_integer_type i = start; i < end; ++i) {
809  krk_integer_type j;
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;
812  }
813  if (j == (krk_integer_type)substr->codesLength) return INTEGER_VAL(i);
814  }
815 
816  return INTEGER_VAL(-1);
817 }
818 
819 KRK_Method(str,index) {
820  KrkValue result = FUNC_NAME(str,find)(argc,argv,hasKw);
821  if (IS_INTEGER(result) && AS_INTEGER(result) == -1) {
822  return krk_runtimeError(vm.exceptions->valueError, "substring not found");
823  }
824  return result;
825 }
826 
827 KRK_Method(str,startswith) {
828  KrkString * substr;
829  int start = 0;
830  int end = self->codesLength;
831  if (!krk_parseArgs(".O!|ii",(const char*[]){"prefix","start","end"}, KRK_BASE_CLASS(str), &substr, &start, &end)) {
832  return NONE_VAL();
833  }
834 
835  WRAP_INDEX(start);
836  WRAP_INDEX(end);
837 
838  krk_unicodeString(self);
839  krk_unicodeString(substr);
840 
841  if (end < start || (size_t)(end - start) < substr->codesLength) return BOOLEAN_VAL(0);
842 
843  for (size_t i = 0; i < substr->codesLength; ++i) {
844  if (KRK_STRING_FAST(self, start + i) != KRK_STRING_FAST(substr,i)) return BOOLEAN_VAL(0);
845  }
846  return BOOLEAN_VAL(1);
847 }
848 
849 KRK_Method(str,endswith) {
850  KrkString * substr;
851  int start = 0;
852  int end = self->codesLength;
853  if (!krk_parseArgs(".O!|ii",(const char*[]){"suffix","start","end"}, KRK_BASE_CLASS(str), &substr, &start, &end)) {
854  return NONE_VAL();
855  }
856 
857  WRAP_INDEX(start);
858  WRAP_INDEX(end);
859 
860  krk_unicodeString(self);
861  krk_unicodeString(substr);
862 
863  if (end < start || (size_t)(end - start) < substr->codesLength) return BOOLEAN_VAL(0);
864 
865  for (size_t i = 0; i < substr->codesLength; ++i) {
866  if (KRK_STRING_FAST(self, (end - i - 1)) != KRK_STRING_FAST(substr,(substr->codesLength - i - 1))) return BOOLEAN_VAL(0);
867  }
868  return BOOLEAN_VAL(1);
869 }
870 
877 KRK_Method(str,__repr__) {
878  METHOD_TAKES_NONE();
879  struct StringBuilder sb = {0};
880  char * end = AS_CSTRING(argv[0]) + AS_STRING(argv[0])->length;
881 
882  /* First count quotes */
883  size_t singles = 0;
884  size_t doubles = 0;
885  for (char * c = AS_CSTRING(argv[0]); c < end; ++c) {
886  if (*c == '\'') singles++;
887  if (*c == '\"') doubles++;
888  }
889 
890  char quote = (singles > doubles) ? '\"' : '\'';
891 
892  pushStringBuilder(&sb, quote);
893 
894  for (char * c = AS_CSTRING(argv[0]); c < end; ++c) {
895  unsigned char ch = *c;
896  int addSlash = 0;
897  switch (ch) {
898  /* XXX: Other non-printables should probably be escaped as well. */
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;
910  default:
911  if (ch < ' ' || ch == 0x7F) {
912  pushStringBuilder(&sb,'\\');
913  pushStringBuilder(&sb,'x');
914  char hex[3];
915  snprintf(hex, 3, "%02x", (unsigned char)*c);
916  pushStringBuilder(&sb,hex[0]);
917  pushStringBuilder(&sb,hex[1]);
918  continue;
919  }
920  break;
921  }
922  if (addSlash) krk_pushStringBuilder(&sb,'\\');
923  krk_pushStringBuilder(&sb,ch);
924  }
925 
926  pushStringBuilder(&sb, quote);
927 
928  return finishStringBuilder(&sb);
929 }
930 
931 KRK_Method(str,encode) {
932  METHOD_TAKES_NONE();
933  return OBJECT_VAL(krk_newBytes(AS_STRING(argv[0])->length, (uint8_t*)AS_CSTRING(argv[0])));
934 }
935 
936 KRK_Method(str,__str__) {
937  METHOD_TAKES_NONE();
938  return argv[0];
939 }
940 
941 void krk_addObjects(void) {
942  KrkValue tmp = FUNC_NAME(str,__add__)(2, (KrkValue[]){krk_peek(1), krk_peek(0)},0);
943  krk_pop(); krk_pop();
944  krk_push(tmp);
945 }
946 
947 KRK_Method(str,__iter__) {
948  METHOD_TAKES_NONE();
949  KrkInstance * output = krk_newInstance(vm.baseClasses->striteratorClass);
950 
951  krk_push(OBJECT_VAL(output));
952  FUNC_NAME(striterator,__init__)(2, (KrkValue[]){krk_peek(0), argv[0]},0);
953  krk_pop();
954 
955  return OBJECT_VAL(output);
956 }
957 
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)
964 
965 KRK_Method(str,isalnum) {
966  CHECK_ALL( (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') );
967 }
968 
969 KRK_Method(str,isalpha) {
970  CHECK_ALL( (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') );
971 }
972 
973 KRK_Method(str,isdigit) {
974  CHECK_ALL( (c >= '0' && c <= '9') );
975 }
976 
977 KRK_Method(str,isxdigit) {
978  CHECK_ALL( (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f') || (c >= '0' && c <= '9') );
979 }
980 
981 KRK_Method(str,isspace) {
982  CHECK_ALL( (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v') );
983 }
984 
985 KRK_Method(str,islower) {
986  CHECK_ALL( (c >= 'a' && c <= 'z') );
987 }
988 
989 KRK_Method(str,isupper) {
990  CHECK_ALL( (c >= 'A' && c <= 'Z') );
991 }
992 
993 KRK_Method(str,lower) {
994  METHOD_TAKES_NONE();
995  struct StringBuilder sb = {0};
996 
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'));
1000  } else {
1001  pushStringBuilder(&sb, self->chars[i]);
1002  }
1003  }
1004 
1005  return finishStringBuilder(&sb);
1006 }
1007 
1008 KRK_Method(str,upper) {
1009  METHOD_TAKES_NONE();
1010  struct StringBuilder sb = {0};
1011 
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'));
1015  } else {
1016  pushStringBuilder(&sb, self->chars[i]);
1017  }
1018  }
1019 
1020  return finishStringBuilder(&sb);
1021 }
1022 
1023 KRK_Method(str,title) {
1024  METHOD_TAKES_NONE();
1025  struct StringBuilder sb = {0};
1026 
1027  int lastWasWhitespace = 1;
1028 
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;
1036  } else {
1037  pushStringBuilder(&sb, self->chars[i]);
1038  lastWasWhitespace = !((self->chars[i] >= 'A' && self->chars[i] <= 'Z') || (self->chars[i] >= 'a' && self->chars[i] <= 'z'));
1039  }
1040  }
1041 
1042  return finishStringBuilder(&sb);
1043 }
1044 
1045 #undef CURRENT_CTYPE
1046 #define CURRENT_CTYPE KrkInstance *
1047 KRK_Method(striterator,__init__) {
1048  METHOD_TAKES_EXACTLY(1);
1049  CHECK_ARG(1,str,KrkString*,base);
1050  krk_push(OBJECT_VAL(self));
1051  krk_attachNamedObject(&self->fields, "s", (KrkObj*)base);
1052  krk_attachNamedValue(&self->fields, "i", INTEGER_VAL(0));
1053  krk_pop();
1054  return NONE_VAL();
1055 }
1056 
1057 KRK_Method(striterator,__call__) {
1058  METHOD_TAKES_NONE();
1059  KrkValue _str;
1060  KrkValue _counter;
1061  const char * errorStr = NULL;
1062  if (!krk_tableGet(&self->fields, OBJECT_VAL(S("s")), &_str) || !IS_STRING(_str)) {
1063  errorStr = "no str pointer";
1064  goto _corrupt;
1065  }
1066  if (!krk_tableGet(&self->fields, OBJECT_VAL(S("i")), &_counter) || !IS_INTEGER(_counter)) {
1067  errorStr = "no index";
1068  goto _corrupt;
1069  }
1070 
1071  if ((size_t)AS_INTEGER(_counter) >= AS_STRING(_str)->codesLength) {
1072  return argv[0];
1073  } else {
1074  krk_attachNamedValue(&self->fields, "i", INTEGER_VAL(AS_INTEGER(_counter)+1));
1075  return FUNC_NAME(str,__getitem__)(2,(KrkValue[]){_str,_counter},3);
1076  }
1077 _corrupt:
1078  return krk_runtimeError(vm.exceptions->typeError, "Corrupt str iterator: %s", errorStr);
1079 }
1080 
1081 
1082 void krk_pushStringBuilder(struct StringBuilder * sb, char c) {
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);
1087  }
1088  sb->bytes[sb->length++] = c;
1089 }
1090 
1091 void krk_pushStringBuilderStr(struct StringBuilder * sb, const char *str, size_t len) {
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);
1097  }
1098  sb->bytes = KRK_GROW_ARRAY(char, sb->bytes, prevcap, sb->capacity);
1099  }
1100  for (size_t i = 0; i < len; ++i) {
1101  sb->bytes[sb->length++] = *(str++);
1102  }
1103 }
1104 
1105 static void _freeStringBuilder(struct StringBuilder * sb) {
1106  KRK_FREE_ARRAY(char,sb->bytes, sb->capacity);
1107  sb->bytes = NULL;
1108  sb->length = 0;
1109  sb->capacity = 0;
1110 }
1112  KrkValue out = OBJECT_VAL(krk_copyString(sb->bytes, sb->length));
1113  _freeStringBuilder(sb);
1114  return out;
1115 }
1116 
1118  KrkValue out = OBJECT_VAL(krk_newBytes(sb->length, (uint8_t*)sb->bytes));
1119  _freeStringBuilder(sb);
1120  return out;
1121 }
1122 
1124  _freeStringBuilder(sb);
1125  return NONE_VAL();
1126 }
1127 
1128 int krk_pushStringBuilderFormatV(struct StringBuilder * sb, const char * fmt, va_list args) {
1129  for (const char * f = fmt; *f; ++f) {
1130  if (*f != '%') {
1131  pushStringBuilder(sb, *f);
1132  continue;
1133  }
1134 
1135  /* Bail on exception */
1136  if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) break;
1137 
1138  ++f;
1139 
1140  int size = ' ';
1141  int len = -1;
1142 
1143  if (*f == 'z') size = *f++;
1144  else if (*f == 'l') size = *f++;
1145  else if (*f == 'L') size = *f++;
1146 
1147  if (*f == '.') {
1148  if (f[1] == '*') {
1149  len = va_arg(args, int);
1150  f += 2;
1151  }
1152  }
1153 
1154  switch (*f) {
1155  case 0: break;
1156  case '%':
1157  pushStringBuilder(sb, '%');
1158  break;
1159 
1160  case 'c': {
1161  char val = (char)va_arg(args, int);
1162  pushStringBuilder(sb, val);
1163  break;
1164  }
1165 
1166  case 's': {
1167  const char * c = va_arg(args, const char *);
1168  pushStringBuilderStr(sb, c, len == -1 ? strlen(c) : (size_t)len);
1169  break;
1170  }
1171 
1172  case 'u': {
1173  size_t val = 0;
1174  if (size == ' ') {
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);
1182  }
1183  char tmp[100];
1184  snprintf(tmp, 32, "%zu", val);
1185  pushStringBuilderStr(sb, tmp, strlen(tmp));
1186  break;
1187  }
1188 
1189  case 'd': {
1190  ssize_t val = 0;
1191  if (size == ' ') {
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);
1199  }
1200  char tmp[100];
1201  snprintf(tmp, 32, "%zd", val);
1202  pushStringBuilderStr(sb, tmp, strlen(tmp));
1203  break;
1204  }
1205 
1206  case 'T': {
1207  KrkValue val = va_arg(args, KrkValue);
1208  const char * typeName = krk_typeName(val);
1209  pushStringBuilderStr(sb, typeName, strlen(typeName));
1210  break;
1211  }
1212 
1213  case 'S': {
1214  KrkString * val = va_arg(args, KrkString*);
1215  pushStringBuilderStr(sb, val->chars, val->length);
1216  break;
1217  }
1218 
1219  case 'R': {
1220  KrkValue val = va_arg(args, KrkValue);
1221  KrkClass * type = krk_getType(val);
1222  if (likely(type->_reprer != NULL)) {
1223  krk_push(val);
1224  KrkValue res = krk_callDirect(type->_reprer, 1);
1225  krk_push(res);
1226  if (IS_STRING(res)) {
1227  pushStringBuilderStr(sb, AS_CSTRING(res), AS_STRING(res)->length);
1228  } else if (!(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) {
1229  krk_runtimeError(vm.exceptions->typeError, "__repr__ returned non-string (type %T)", res);
1230  }
1231  krk_pop();
1232  }
1233  break;
1234  }
1235 
1236  case 'p': {
1237  uintptr_t val = va_arg(args, uintptr_t);
1238  char tmp[100];
1239  snprintf(tmp, 32, "0x%zx", (size_t)val);
1240  pushStringBuilderStr(sb, tmp, strlen(tmp));
1241  break;
1242  }
1243 
1244  default: {
1245  va_arg(args, void*);
1246  pushStringBuilderStr(sb, "(unsupported: ", 14);
1247  pushStringBuilder(sb, *f);
1248  pushStringBuilder(sb, ')');
1249  break;
1250  }
1251  }
1252  }
1253 
1254  if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return 0;
1255  return 1;
1256 }
1257 
1258 int krk_pushStringBuilderFormat(struct StringBuilder * sb, const char * fmt, ...) {
1259  va_list args;
1260  va_start(args, fmt);
1261  int result = krk_pushStringBuilderFormatV(sb,fmt,args);
1262  va_end(args);
1263  return result;
1264 }
1265 
1266 KrkValue krk_stringFromFormat(const char * fmt, ...) {
1267  struct StringBuilder sb = {0};
1268  va_list args;
1269  va_start(args, fmt);
1270  int result = krk_pushStringBuilderFormatV(&sb,fmt,args);
1271  va_end(args);
1272  if (!result) return krk_discardStringBuilder(&sb);
1273  return krk_finishStringBuilder(&sb);
1274 }
1275 
1276 _noexport
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;
1280  str->allocSize = 0;
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);
1314 
1315  /* TODO these are not properly Unicode-aware */
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);
1323 
1324  /* Not recommended in their current forms, but here for some Python compatibility */
1325  BIND_METHOD(str,lower);
1326  BIND_METHOD(str,upper);
1327  BIND_METHOD(str,title);
1328 
1329  krk_defineNative(&str->methods,"__delitem__",FUNC_NAME(str,__setitem__));
1330  krk_finalizeClass(str);
1331  KRK_DOC(str, "Obtain a string representation of an object.");
1332 
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__);
1337  krk_finalizeClass(striterator);
1338 }
1339 
KrkValue krk_runtimeError(KrkClass *type, const char *fmt,...)
Produce and raise an exception with a formatted message.
Definition: exceptions.c:460
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.
Definition: obj_long.c:2820
KrkStringType
String compact storage type.
Definition: object.h:81
Internal header.
KrkBytes * krk_newBytes(size_t length, uint8_t *source)
Create a new byte array.
Definition: object.c:367
Type object.
Definition: object.h:215
KrkObj * _tostr
__str__ Called to produce a string from an instance
Definition: object.h:230
KrkObj * _reprer
__repr__ Called to create a reproducible string representation of an instance
Definition: object.h:229
size_t allocSize
Size to allocate when creating instances of this class.
Definition: object.h:222
KrkObj obj
Base.
Definition: object.h:216
KrkTable methods
General attributes table.
Definition: object.h:218
void krk_finalizeClass(KrkClass *_class)
Finalize a class by collecting pointers to core methods.
Definition: vm.c:189
int krk_bindMethod(KrkClass *_class, KrkString *name)
Perform method binding on the stack.
Definition: vm.c:1655
An object of a class.
Definition: object.h:281
KrkInstance * krk_newInstance(KrkClass *_class)
Create a new instance of the given class.
Definition: object.c:343
KrkValue krk_list_of(int argc, const KrkValue argv[], int hasKw)
Create a list object.
Definition: obj_list.c:30
The most basic object type.
Definition: object.h:41
uint16_t flags
General object flags, mostly related to garbage collection.
Definition: object.h:43
Immutable sequence of Unicode codepoints.
Definition: object.h:93
uint32_t krk_unicodeCodepoint(KrkString *string, size_t index)
Obtain the codepoint at a given index in a string.
Definition: object.c:162
void * krk_unicodeString(KrkString *string)
Ensure that a codepoint representation of a string is available.
Definition: object.c:153
KrkString * krk_copyString(const char *chars, size_t length)
Obtain a string object representation of the given C string.
Definition: object.c:224
size_t codesLength
String length in Unicode codepoints.
Definition: object.h:96
char * chars
UTF8 canonical data.
Definition: object.h:97
size_t length
String length in bytes.
Definition: object.h:95
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,...
Definition: object.c:241
size_t krk_codepointToBytes(krk_integer_type value, unsigned char *out)
Convert an integer codepoint to a UTF-8 byte representation.
Definition: object.c:38
int krk_tableGet(KrkTable *table, KrkValue key, KrkValue *value)
Obtain the value associated with a key in a table.
Definition: table.c:211
void krk_attachNamedObject(KrkTable *table, const char name[], KrkObj *obj)
Attach an object to an attribute table.
Definition: vm.c:808
KrkNative * krk_defineNative(KrkTable *table, const char *name, NativeFn function)
Attach a native C function to an attribute table.
Definition: vm.c:155
void krk_attachNamedValue(KrkTable *table, const char name[], KrkValue obj)
Attach a value to an attribute table.
Definition: vm.c:794
int flags
Definition: vm.h:165
Immutable sequence of arbitrary values.
Definition: object.h:323
KrkValueArray values
Stores the length, capacity, and actual values of the tuple.
Definition: object.h:325
KrkTuple * krk_newTuple(size_t length)
Create a new tuple.
Definition: object.c:357
KrkValue * values
Definition: value.h:78
void krk_writeValueArray(KrkValueArray *array, KrkValue value)
Add a value to a value array.
Definition: value.c:17
size_t count
Definition: value.h:77
Stack reference or primative value.
const char * krk_typeName(KrkValue value)
Get the name of the type of a value.
Definition: vm.c:984
KrkClass * krk_getType(KrkValue value)
Get the class representing a value.
Definition: vm.c:240
Inline flexible string array.
Definition: util.h:162
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.
Definition: obj_str.c:1091
#define krk_parseArgs(f, n,...)
Parse arguments to a function while accepting keyword arguments.
Definition: util.h:360
KrkValue krk_finishStringBuilderBytes(struct StringBuilder *sb)
Finalize a string builder in a bytes object.
Definition: obj_str.c:1117
KrkValue krk_discardStringBuilder(struct StringBuilder *sb)
Discard the contents of a string builder.
Definition: obj_str.c:1123
int krk_unpackIterable(KrkValue iterable, void *context, int callback(void *, const KrkValue *, size_t))
Unpack an iterable.
Definition: builtins.c:387
KrkValue krk_finishStringBuilder(struct StringBuilder *sb)
Finalize a string builder into a string object.
Definition: obj_str.c:1111
void krk_pushStringBuilder(struct StringBuilder *sb, char c)
Add a character to the end of a string builder.
Definition: obj_str.c:1082
#define KRK_DOC(thing, text)
Attach documentation to a thing of various types.
Definition: util.h:304
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.
Definition: vm.c:732
#define vm
Convenience macro for namespacing.
Definition: vm.h:257
KrkValue krk_pop(void)
Pop the top of the stack.
Definition: vm.c:131
void krk_addObjects(void)
Concatenate two strings.
Definition: obj_str.c:941
void krk_push(KrkValue value)
Push a stack value.
Definition: vm.c:118
KrkValue krk_callDirect(KrkObj *callable, int argCount)
Call a closure or native function with argCount arguments.
Definition: vm.c:740
KrkValue krk_peek(int distance)
Peek down from the top of the stack.
Definition: vm.c:139