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 = 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 FLOATING_VAL(strtod(AS_CSTRING(argv[0]),NULL));
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  METHOD_TAKES_EXACTLY(1); /* I know the Python versions of these take optional start, end... */
829  CHECK_ARG(1,str,KrkString*,prefix);
830  return BOOLEAN_VAL(substringMatch(self->chars,self->length,prefix->chars,prefix->length));
831 }
832 
833 KRK_Method(str,endswith) {
834  METHOD_TAKES_EXACTLY(1); /* I know the Python versions of these take optional start, end... */
835  CHECK_ARG(1,str,KrkString*,suffix);
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));
839 }
840 
847 KRK_Method(str,__repr__) {
848  METHOD_TAKES_NONE();
849  struct StringBuilder sb = {0};
850  char * end = AS_CSTRING(argv[0]) + AS_STRING(argv[0])->length;
851 
852  /* First count quotes */
853  size_t singles = 0;
854  size_t doubles = 0;
855  for (char * c = AS_CSTRING(argv[0]); c < end; ++c) {
856  if (*c == '\'') singles++;
857  if (*c == '\"') doubles++;
858  }
859 
860  char quote = (singles > doubles) ? '\"' : '\'';
861 
862  pushStringBuilder(&sb, quote);
863 
864  for (char * c = AS_CSTRING(argv[0]); c < end; ++c) {
865  switch (*c) {
866  /* XXX: Other non-printables should probably be escaped as well. */
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;
878  default: {
879  if ((unsigned char)*c < ' ' || (unsigned char)*c == 0x7F) {
880  pushStringBuilder(&sb,'\\');
881  pushStringBuilder(&sb,'x');
882  char hex[3];
883  snprintf(hex, 3, "%02x", (unsigned char)*c);
884  pushStringBuilder(&sb,hex[0]);
885  pushStringBuilder(&sb,hex[1]);
886  } else {
887  pushStringBuilder(&sb,*c);
888  }
889  break;
890  }
891  }
892  }
893 
894  pushStringBuilder(&sb, quote);
895 
896  return finishStringBuilder(&sb);
897 }
898 
899 KRK_Method(str,encode) {
900  METHOD_TAKES_NONE();
901  return OBJECT_VAL(krk_newBytes(AS_STRING(argv[0])->length, (uint8_t*)AS_CSTRING(argv[0])));
902 }
903 
904 KRK_Method(str,__str__) {
905  METHOD_TAKES_NONE();
906  return argv[0];
907 }
908 
909 void krk_addObjects(void) {
910  KrkValue tmp = FUNC_NAME(str,__add__)(2, (KrkValue[]){krk_peek(1), krk_peek(0)},0);
911  krk_pop(); krk_pop();
912  krk_push(tmp);
913 }
914 
915 KRK_Method(str,__iter__) {
916  METHOD_TAKES_NONE();
917  KrkInstance * output = krk_newInstance(vm.baseClasses->striteratorClass);
918 
919  krk_push(OBJECT_VAL(output));
920  FUNC_NAME(striterator,__init__)(2, (KrkValue[]){krk_peek(0), argv[0]},0);
921  krk_pop();
922 
923  return OBJECT_VAL(output);
924 }
925 
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)
932 
933 KRK_Method(str,isalnum) {
934  CHECK_ALL( (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') );
935 }
936 
937 KRK_Method(str,isalpha) {
938  CHECK_ALL( (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') );
939 }
940 
941 KRK_Method(str,isdigit) {
942  CHECK_ALL( (c >= '0' && c <= '9') );
943 }
944 
945 KRK_Method(str,isxdigit) {
946  CHECK_ALL( (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f') || (c >= '0' && c <= '9') );
947 }
948 
949 KRK_Method(str,isspace) {
950  CHECK_ALL( (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v') );
951 }
952 
953 KRK_Method(str,islower) {
954  CHECK_ALL( (c >= 'a' && c <= 'z') );
955 }
956 
957 KRK_Method(str,isupper) {
958  CHECK_ALL( (c >= 'A' && c <= 'Z') );
959 }
960 
961 KRK_Method(str,lower) {
962  METHOD_TAKES_NONE();
963  struct StringBuilder sb = {0};
964 
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'));
968  } else {
969  pushStringBuilder(&sb, self->chars[i]);
970  }
971  }
972 
973  return finishStringBuilder(&sb);
974 }
975 
976 KRK_Method(str,upper) {
977  METHOD_TAKES_NONE();
978  struct StringBuilder sb = {0};
979 
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'));
983  } else {
984  pushStringBuilder(&sb, self->chars[i]);
985  }
986  }
987 
988  return finishStringBuilder(&sb);
989 }
990 
991 KRK_Method(str,title) {
992  METHOD_TAKES_NONE();
993  struct StringBuilder sb = {0};
994 
995  int lastWasWhitespace = 1;
996 
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;
1004  } else {
1005  pushStringBuilder(&sb, self->chars[i]);
1006  lastWasWhitespace = !((self->chars[i] >= 'A' && self->chars[i] <= 'Z') || (self->chars[i] >= 'a' && self->chars[i] <= 'z'));
1007  }
1008  }
1009 
1010  return finishStringBuilder(&sb);
1011 }
1012 
1013 #undef CURRENT_CTYPE
1014 #define CURRENT_CTYPE KrkInstance *
1015 KRK_Method(striterator,__init__) {
1016  METHOD_TAKES_EXACTLY(1);
1017  CHECK_ARG(1,str,KrkString*,base);
1018  krk_push(OBJECT_VAL(self));
1019  krk_attachNamedObject(&self->fields, "s", (KrkObj*)base);
1020  krk_attachNamedValue(&self->fields, "i", INTEGER_VAL(0));
1021  krk_pop();
1022  return NONE_VAL();
1023 }
1024 
1025 KRK_Method(striterator,__call__) {
1026  METHOD_TAKES_NONE();
1027  KrkValue _str;
1028  KrkValue _counter;
1029  const char * errorStr = NULL;
1030  if (!krk_tableGet(&self->fields, OBJECT_VAL(S("s")), &_str) || !IS_STRING(_str)) {
1031  errorStr = "no str pointer";
1032  goto _corrupt;
1033  }
1034  if (!krk_tableGet(&self->fields, OBJECT_VAL(S("i")), &_counter) || !IS_INTEGER(_counter)) {
1035  errorStr = "no index";
1036  goto _corrupt;
1037  }
1038 
1039  if ((size_t)AS_INTEGER(_counter) >= AS_STRING(_str)->codesLength) {
1040  return argv[0];
1041  } else {
1042  krk_attachNamedValue(&self->fields, "i", INTEGER_VAL(AS_INTEGER(_counter)+1));
1043  return FUNC_NAME(str,__getitem__)(2,(KrkValue[]){_str,_counter},3);
1044  }
1045 _corrupt:
1046  return krk_runtimeError(vm.exceptions->typeError, "Corrupt str iterator: %s", errorStr);
1047 }
1048 
1049 
1050 void krk_pushStringBuilder(struct StringBuilder * sb, char c) {
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);
1055  }
1056  sb->bytes[sb->length++] = c;
1057 }
1058 
1059 void krk_pushStringBuilderStr(struct StringBuilder * sb, const char *str, size_t len) {
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);
1065  }
1066  sb->bytes = GROW_ARRAY(char, sb->bytes, prevcap, sb->capacity);
1067  }
1068  for (size_t i = 0; i < len; ++i) {
1069  sb->bytes[sb->length++] = *(str++);
1070  }
1071 }
1072 
1073 static void _freeStringBuilder(struct StringBuilder * sb) {
1074  FREE_ARRAY(char,sb->bytes, sb->capacity);
1075  sb->bytes = NULL;
1076  sb->length = 0;
1077  sb->capacity = 0;
1078 }
1080  KrkValue out = OBJECT_VAL(krk_copyString(sb->bytes, sb->length));
1081  _freeStringBuilder(sb);
1082  return out;
1083 }
1084 
1086  KrkValue out = OBJECT_VAL(krk_newBytes(sb->length, (uint8_t*)sb->bytes));
1087  _freeStringBuilder(sb);
1088  return out;
1089 }
1090 
1092  _freeStringBuilder(sb);
1093  return NONE_VAL();
1094 }
1095 
1096 int krk_pushStringBuilderFormatV(struct StringBuilder * sb, const char * fmt, va_list args) {
1097  for (const char * f = fmt; *f; ++f) {
1098  if (*f != '%') {
1099  pushStringBuilder(sb, *f);
1100  continue;
1101  }
1102 
1103  /* Bail on exception */
1104  if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) {
1105  return 0;
1106  }
1107 
1108  ++f;
1109 
1110  int size = ' ';
1111  int len = -1;
1112 
1113  if (*f == 'z') size = *f++;
1114  else if (*f == 'l') size = *f++;
1115  else if (*f == 'L') size = *f++;
1116 
1117  if (*f == '.') {
1118  if (f[1] == '*') {
1119  len = va_arg(args, int);
1120  f += 2;
1121  }
1122  }
1123 
1124  switch (*f) {
1125  case 0: break;
1126  case '%':
1127  pushStringBuilder(sb, '%');
1128  break;
1129 
1130  case 'c': {
1131  char val = (char)va_arg(args, int);
1132  pushStringBuilder(sb, val);
1133  break;
1134  }
1135 
1136  case 's': {
1137  const char * c = va_arg(args, const char *);
1138  pushStringBuilderStr(sb, c, len == -1 ? strlen(c) : (size_t)len);
1139  break;
1140  }
1141 
1142  case 'u': {
1143  size_t val = 0;
1144  if (size == ' ') {
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);
1152  }
1153  char tmp[100];
1154  snprintf(tmp, 32, "%zu", val);
1155  pushStringBuilderStr(sb, tmp, strlen(tmp));
1156  break;
1157  }
1158 
1159  case 'd': {
1160  ssize_t val = 0;
1161  if (size == ' ') {
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);
1169  }
1170  char tmp[100];
1171  snprintf(tmp, 32, "%zd", val);
1172  pushStringBuilderStr(sb, tmp, strlen(tmp));
1173  break;
1174  }
1175 
1176  case 'T': {
1177  KrkValue val = va_arg(args, KrkValue);
1178  const char * typeName = krk_typeName(val);
1179  pushStringBuilderStr(sb, typeName, strlen(typeName));
1180  break;
1181  }
1182 
1183  case 'S': {
1184  KrkString * val = va_arg(args, KrkString*);
1185  pushStringBuilderStr(sb, val->chars, val->length);
1186  break;
1187  }
1188 
1189  case 'R': {
1190  KrkValue val = va_arg(args, KrkValue);
1191  KrkClass * type = krk_getType(val);
1192  if (likely(type->_reprer != NULL)) {
1193  krk_push(val);
1194  KrkValue res = krk_callDirect(type->_reprer, 1);
1195  krk_push(res);
1196  if (IS_STRING(res)) {
1197  pushStringBuilderStr(sb, AS_CSTRING(res), AS_STRING(res)->length);
1198  }
1199  krk_pop();
1200  }
1201  break;
1202  }
1203 
1204  case 'p': {
1205  uintptr_t val = va_arg(args, uintptr_t);
1206  char tmp[100];
1207  snprintf(tmp, 32, "0x%zx", (size_t)val);
1208  pushStringBuilderStr(sb, tmp, strlen(tmp));
1209  break;
1210  }
1211 
1212  default: {
1213  va_arg(args, void*);
1214  pushStringBuilderStr(sb, "(unsupported: ", 14);
1215  pushStringBuilder(sb, *f);
1216  pushStringBuilder(sb, ')');
1217  break;
1218  }
1219  }
1220  }
1221 
1222  return 1;
1223 }
1224 
1225 int krk_pushStringBuilderFormat(struct StringBuilder * sb, const char * fmt, ...) {
1226  va_list args;
1227  va_start(args, fmt);
1228  int result = krk_pushStringBuilderFormatV(sb,fmt,args);
1229  va_end(args);
1230  return result;
1231 }
1232 
1233 KrkValue krk_stringFromFormat(const char * fmt, ...) {
1234  struct StringBuilder sb = {0};
1235  va_list args;
1236  va_start(args, fmt);
1237  int result = krk_pushStringBuilderFormatV(&sb,fmt,args);
1238  va_end(args);
1239  if (!result) return krk_discardStringBuilder(&sb);
1240  return krk_finishStringBuilder(&sb);
1241 }
1242 
1243 _noexport
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;
1247  str->allocSize = 0;
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);
1281 
1282  /* TODO these are not properly Unicode-aware */
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);
1290 
1291  /* Not recommended in their current forms, but here for some Python compatibility */
1292  BIND_METHOD(str,lower);
1293  BIND_METHOD(str,upper);
1294  BIND_METHOD(str,title);
1295 
1296  krk_defineNative(&str->methods,"__delitem__",FUNC_NAME(str,__setitem__));
1297  krk_finalizeClass(str);
1298  KRK_DOC(str, "Obtain a string representation of an object.");
1299 
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__);
1304  krk_finalizeClass(striterator);
1305 }
1306 
KrkValue krk_runtimeError(KrkClass *type, const char *fmt,...)
Produce and raise an exception with a formatted message.
Definition: exceptions.c:445
Functions for dealing with garbage collection and memory allocation.
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:363
Type object.
Definition: object.h:189
KrkObj * _tostr
__str__ Called to produce a string from an instance
Definition: object.h:204
KrkObj * _reprer
__repr__ Called to create a reproducible string representation of an instance
Definition: object.h:203
size_t allocSize
Size to allocate when creating instances of this class.
Definition: object.h:196
KrkObj obj
Base.
Definition: object.h:190
KrkTable methods
General attributes table.
Definition: object.h:192
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.
Definition: vm.c:1693
An object of a class.
Definition: object.h:255
KrkInstance * krk_newInstance(KrkClass *_class)
Create a new instance of the given class.
Definition: object.c:339
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:161
void * krk_unicodeString(KrkString *string)
Ensure that a codepoint representation of a string is available.
Definition: object.c:152
KrkString * krk_copyString(const char *chars, size_t length)
Obtain a string object representation of the given C string.
Definition: object.c:221
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:238
size_t krk_codepointToBytes(krk_integer_type value, unsigned char *out)
Convert an integer codepoint to a UTF-8 byte representation.
Definition: object.c:37
int krk_tableGet(KrkTable *table, KrkValue key, KrkValue *value)
Obtain the value associated with a key in a table.
Definition: table.c:178
void krk_attachNamedObject(KrkTable *table, const char name[], KrkObj *obj)
Attach an object to an attribute table.
Definition: vm.c:839
KrkNative * krk_defineNative(KrkTable *table, const char *name, NativeFn function)
Attach a native C function to an attribute table.
Definition: vm.c:194
void krk_attachNamedValue(KrkTable *table, const char name[], KrkValue obj)
Attach a value to an attribute table.
Definition: vm.c:825
int flags
Definition: vm.h:174
Immutable sequence of arbitrary values.
Definition: object.h:297
KrkValueArray values
Stores the length, capacity, and actual values of the tuple.
Definition: object.h:299
KrkTuple * krk_newTuple(size_t length)
Create a new tuple.
Definition: object.c:353
KrkValue * values
Definition: value.h:73
void krk_writeValueArray(KrkValueArray *array, KrkValue value)
Add a value to a value array.
Definition: value.c:17
size_t count
Definition: value.h:72
Stack reference or primative value.
const char * krk_typeName(KrkValue value)
Get the name of the type of a value.
Definition: vm.c:1023
KrkClass * krk_getType(KrkValue value)
Get the class representing a value.
Definition: vm.c:275
Inline flexible string array.
Definition: util.h:150
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:1059
#define krk_parseArgs(f, n,...)
Parse arguments to a function while accepting keyword arguments.
Definition: util.h:348
KrkValue krk_finishStringBuilderBytes(struct StringBuilder *sb)
Finalize a string builder in a bytes object.
Definition: obj_str.c:1085
KrkValue krk_discardStringBuilder(struct StringBuilder *sb)
Discard the contents of a string builder.
Definition: obj_str.c:1091
int krk_unpackIterable(KrkValue iterable, void *context, int callback(void *, const KrkValue *, size_t))
Unpack an iterable.
Definition: builtins.c:380
KrkValue krk_finishStringBuilder(struct StringBuilder *sb)
Finalize a string builder into a string object.
Definition: obj_str.c:1079
void krk_pushStringBuilder(struct StringBuilder *sb, char c)
Add a character to the end of a string builder.
Definition: obj_str.c:1050
#define KRK_DOC(thing, text)
Attach documentation to a thing of various types.
Definition: util.h:292
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.
Definition: vm.c:763
#define vm
Convenience macro for namespacing.
Definition: vm.h:267
KrkValue krk_pop(void)
Pop the top of the stack.
Definition: vm.c:170
threadLocal KrkThreadState krk_currentThread
Thread-local VM state.
void krk_addObjects(void)
Concatenate two strings.
Definition: obj_str.c:909
void krk_push(KrkValue value)
Push a stack value.
Definition: vm.c:157
KrkValue krk_callDirect(KrkObj *callable, int argCount)
Call a closure or native function with argCount arguments.
Definition: vm.c:771
KrkValue krk_peek(int distance)
Peek down from the top of the stack.
Definition: vm.c:178