obj_numeric.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 #undef bool
10 
11 #define IS_NoneType(o) (IS_NONE(o))
12 #define AS_NoneType(o) ((char)0)
13 
14 #define CURRENT_CTYPE krk_integer_type
15 #define CURRENT_NAME self
16 
17 extern KrkValue krk_int_from_float(double val);
18 
19 KRK_StaticMethod(int,__new__) {
20  KrkObj *cls;
21  int has_x = 0;
22  KrkValue x = NONE_VAL();
23  int has_base = 0;
24  int base = 10;
25 
26  /* Most common case */
27  if (!hasKw && argc == 2) {
28  x = argv[1];
29  goto _just_x;
30  }
31 
32  if (!krk_parseArgs("O|V?i?:int", (const char*[]){"","","base"},
33  &cls, &has_x, &x, &has_base, &base)) return NONE_VAL();
34 
35  if (has_base && (base < 2 || base > 36) && base != 0) {
36  return krk_runtimeError(vm.exceptions->valueError, "base must be 0 or between 2 and 36");
37  }
38 
39  if (!has_x && has_base) {
40  return krk_runtimeError(vm.exceptions->typeError, "missing str argument");
41  }
42 
43  if (!has_x) {
44  return INTEGER_VAL(0);
45  }
46 
47  if (has_base && !IS_STRING(x)) {
48  return krk_runtimeError(vm.exceptions->typeError, "can not convert non-str with explicit base");
49  }
50 
51 _just_x:
52 
53  if (IS_INTEGER(x)) return INTEGER_VAL(AS_INTEGER(x));
54 #ifndef KRK_NO_FLOAT
55  if (IS_FLOATING(x)) return krk_int_from_float(AS_FLOATING(x));
56 #endif
57 
58  if (IS_STRING(x)) {
59  KrkValue result = krk_parse_int(AS_CSTRING(x), AS_STRING(x)->length, base);
60  if (IS_NONE(result)) {
61  return krk_runtimeError(vm.exceptions->valueError,
62  "invalid literal for int() with base %zd: %R", (ssize_t)base, x);
63  }
64  return result;
65  }
66 
67  if (krk_isInstanceOf(x, KRK_BASE_CLASS(long))) return x;
68  return krk_runtimeError(vm.exceptions->typeError, "%s() argument must be a string or a number, not '%T'", "int", x);
69 }
70 
71 KRK_Method(int,__repr__) {
72  char tmp[100];
73  size_t l = snprintf(tmp, 100, PRIkrk_int, self);
74  return OBJECT_VAL(krk_copyString(tmp, l));
75 }
76 
77 KRK_Method(int,__int__) { return argv[0]; }
78 
79 #ifndef KRK_NO_FLOAT
80 KRK_Method(int,__float__) { return FLOATING_VAL(self); }
81 #endif
82 
83 KRK_Method(int,__chr__) {
84  unsigned char bytes[5] = {0};
85  size_t len = krk_codepointToBytes(self, bytes);
86  return OBJECT_VAL(krk_copyString((char*)bytes, len));
87 }
88 
89 KRK_Method(int,__eq__) {
90  METHOD_TAKES_EXACTLY(1);
91  if (likely(IS_INTEGER(argv[1]))) return BOOLEAN_VAL(self == AS_INTEGER(argv[1]));
92 #ifndef KRK_NO_FLOAT
93  else if (IS_FLOATING(argv[1])) return BOOLEAN_VAL(self == AS_FLOATING(argv[1]));
94 #endif
95  return NOTIMPL_VAL();
96 }
97 
98 KRK_Method(int,__hash__) {
99  return INTEGER_VAL((uint32_t)AS_INTEGER(argv[0]));
100 }
101 
102 static inline int matches(char c, const char * options) {
103  for (const char * o = options; *o; ++o) {
104  if (*o == c) return 1;
105  }
106  return 0;
107 }
108 
109 const char * krk_parseCommonFormatSpec(struct ParsedFormatSpec *result, const char * spec, size_t length) {
110  result->fill = " ";
111  result->fillSize = 1;
112 
113  if (length > 1) {
114  /* How wide is the first character? */
115  int i = 1;
116  if ((spec[0] & 0xC0) == 0xC0) { /* wider than one byte */
117  while ((spec[i] & 0xc0) == 0x80) i++; /* count continuation bytes */
118  }
119  /* Is the character after it an alignment? */
120  if (matches(spec[i],"<>=^")) {
121  result->fill = spec;
122  result->fillSize = i;
123  spec += i;
124  }
125  }
126 
127  if (matches(*spec,"<>=^")) {
128  result->align = *spec;
129  spec++;
130  }
131 
132  if (matches(*spec,"+- ")) {
133  result->sign = *spec;
134  spec++;
135  }
136 
137  if (*spec == '#') {
138  result->alt = 1;
139  spec++;
140  }
141 
142  if (!result->align && *spec == '0') {
143  result->align = '=';
144  result->fill = "0";
145  result->fillSize = 1;
146  spec++;
147  }
148 
149  if (matches(*spec,"0123456789")) {
150  result->hasWidth = 1;
151  do {
152  result->width *= 10;
153  result->width += (*spec - '0');
154  spec++;
155  } while (matches(*spec,"0123456789"));
156  }
157 
158  if (matches(*spec, "_,")) {
159  result->sep = *spec;
160  spec++;
161  }
162 
163  if (*spec == '.') {
164  spec++;
165  if (!matches(*spec,"0123456789")) {
166  krk_runtimeError(vm.exceptions->valueError, "Format specifier missing precision");
167  return NULL;
168  }
169  result->hasPrecision = 1;
170  while (matches(*spec,"0123456789")) {
171  result->prec *= 10;
172  result->prec += (*spec - '0');
173  spec++;
174  }
175  }
176 
177  if (*spec && spec[1] != 0) {
178  krk_runtimeError(vm.exceptions->valueError, "Invalid format specifier");
179  return NULL;
180  }
181 
182  return spec;
183 }
184 
185 typedef int (*fmtCallback)(void *, int, int *);
186 KrkValue krk_doFormatString(const char * typeName, KrkString * format_spec, int positive, void * abs, fmtCallback callback, fmtCallback (*prepCallback)(void*,int)) {
187 
188  struct ParsedFormatSpec opts = {0};
189  const char * spec = krk_parseCommonFormatSpec(&opts, format_spec->chars, format_spec->length);
190  if (!spec) return NONE_VAL();
191 
192  const char * altPrefix = NULL;
193  const char * conversions = "0123456789abcdef";
194  int base = 0;
195 
196  switch (*spec) {
197  case 0: /* unspecified */
198  case 'd': /* decimal integer */
199  base = 10;
200  break;
201  case 'b': /* binary */
202  base = 2;
203  altPrefix = "0b";
204  break;
205  case 'o': /* octal */
206  base = 8;
207  altPrefix = "0o";
208  break;
209  case 'x': /* hex */
210  base = 16;
211  altPrefix = "0x";
212  break;
213  case 'X': /* HEX */
214  base = 16;
215  conversions = "0123456789ABCDEF";
216  altPrefix = "0X";
217  break;
218 
219  case 'c': /* unicode codepoint */
220  return krk_runtimeError(vm.exceptions->notImplementedError,
221  "TODO: 'c' format specifier");
222 
223  case 'n': /* use local-specific separators (TODO) */
224  return krk_runtimeError(vm.exceptions->notImplementedError,
225  "TODO: 'n' format specifier");
226 
227  default:
228  return krk_runtimeError(vm.exceptions->valueError,
229  "Unknown format code '%c' for object of type '%s'",
230  *spec,
231  typeName);
232  }
233 
234  if (!opts.sign) opts.sign = '-';
235  if (!opts.align) opts.align = '>';
236 
237  struct StringBuilder sb = {0};
238 
239  int width = opts.width;
240  int l = 0;
241 
242  if (opts.alt && altPrefix && width > 2) width -= 2;
243  if ((!positive || opts.sign == '+') && width > 1) width--;
244 
245  int digits = 0;
246  int sepcount = (opts.sep == ',' || base == 10) ? 3 : 4;
247  int more = 0;
248 
249  if (prepCallback) callback = prepCallback(abs, base);
250 
251  do {
252  int digit = callback(abs, base, &more);
253 
254  if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) {
255  discardStringBuilder(&sb);
256  return NONE_VAL();
257  }
258 
259  if (digits && !more && digit == 0) {
260  /* Add backwards */
261  for (int i = 0; i < opts.fillSize; ++i) {
262  pushStringBuilder(&sb, opts.fill[opts.fillSize-1-i]);
263  }
264  } else {
265  pushStringBuilder(&sb, conversions[digit]);
266  }
267  l++;
268  digits++;
269 
270  if (opts.sep && !(digits % sepcount) && (more || (opts.align == '=' && l < width))) {
271  pushStringBuilder(&sb, opts.sep);
272  l++;
273  if (opts.align == '=' && l == width) {
274  /* Add backwards */
275  for (int i = 0; i < opts.fillSize; ++i) {
276  pushStringBuilder(&sb, opts.fill[opts.fillSize-1-i]);
277  }
278  }
279  }
280  } while (more || (opts.align == '=' && l < width));
281 
282  if (opts.alt && altPrefix) {
283  pushStringBuilder(&sb, altPrefix[1]);
284  pushStringBuilder(&sb, altPrefix[0]);
285  }
286 
287  if (!positive || opts.sign == '+') {
288  pushStringBuilder(&sb, positive ? '+' : '-');
289  }
290 
291  if (opts.align == '>') {
292  while (l < width) {
293  for (int i = 0; i < opts.fillSize; ++i) {
294  pushStringBuilder(&sb, opts.fill[opts.fillSize-1-i]);
295  }
296  l++;
297  }
298  } else if (opts.align == '^') {
299  int remaining = (width - l) / 2;
300  for (int i = 0; i < remaining; ++i) {
301  for (int i = 0; i < opts.fillSize; ++i) {
302  pushStringBuilder(&sb, opts.fill[opts.fillSize-1-i]);
303  }
304  l++;
305  }
306  }
307 
308  for (size_t i = 0; i < sb.length / 2; ++i) {
309  char t = sb.bytes[i];
310  sb.bytes[i] = sb.bytes[sb.length - i - 1];
311  sb.bytes[sb.length - i - 1] = t;
312  }
313 
314  if (opts.align == '<' || opts.align == '^') {
315  while (l < width) {
316  pushStringBuilderStr(&sb, opts.fill, opts.fillSize);
317  l++;
318  }
319  }
320 
321  return finishStringBuilder(&sb);
322 }
323 
324 static int formatIntCallback(void * a, int base, int *more) {
325  krk_integer_type v = *(krk_integer_type*)a;
326  int digit = v % base;
327  v /= base;
328  *(krk_integer_type*)a = v;
329  *more = v > 0;
330  return digit;
331 }
332 
333 
334 KRK_Method(int,__format__) {
335  METHOD_TAKES_EXACTLY(1);
336  CHECK_ARG(1,str,KrkString*,format_spec);
337 
338  krk_integer_type abs = self < 0 ? -self : self;
339 
340  return krk_doFormatString(krk_typeName(argv[0]), format_spec,
341  self >= 0,
342  &abs,
343  formatIntCallback, NULL);
344 }
345 
356 #define OVERFLOW_CHECKED_INT_OPERATION(name,operator) \
357  extern KrkValue krk_long_coerced_ ## name (krk_integer_type a, krk_integer_type b); \
358  _noexport \
359  KrkValue krk_int_op_ ## name (krk_integer_type a, krk_integer_type b) { \
360  if (likely((int32_t)a == a && (int32_t)b == b)) { \
361  int32_t result_one = a operator b; \
362  int64_t result_two = a operator b; \
363  if (likely(result_one == result_two)) return INTEGER_VAL(result_two); \
364  } \
365  return krk_long_coerced_ ## name (a, b); \
366  }
367 
368 OVERFLOW_CHECKED_INT_OPERATION(add,+)
369 OVERFLOW_CHECKED_INT_OPERATION(sub,-)
370 OVERFLOW_CHECKED_INT_OPERATION(mul,*)
371 
372 #ifndef KRK_NO_FLOAT
373 # define MAYBE_FLOAT(x) x
374 #else
375 # define MAYBE_FLOAT(x) krk_runtimeError(vm.exceptions->valueError, "no float support")
376 #endif
377 
378 #define BASIC_BIN_OP(name,operator) \
379  KRK_Method(int,__ ## name ## __) { \
380  if (likely(IS_INTEGER(argv[1]))) return krk_int_op_ ## name(self, AS_INTEGER(argv[1])); \
381  else if (likely(IS_FLOATING(argv[1]))) return MAYBE_FLOAT(FLOATING_VAL((double)self operator AS_FLOATING(argv[1]))); \
382  return NOTIMPL_VAL(); \
383  } \
384  KRK_Method(int,__r ## name ## __) { \
385  if (likely(IS_INTEGER(argv[1]))) return krk_int_op_ ## name(AS_INTEGER(argv[1]), self); \
386  else if (likely(IS_FLOATING(argv[1]))) return MAYBE_FLOAT(FLOATING_VAL(AS_FLOATING(argv[1]) operator (double)self)); \
387  return NOTIMPL_VAL(); \
388  }
389 
390 #define INT_ONLY_BIN_OP(name,operator) \
391  KRK_Method(int,__ ## name ## __) { \
392  if (likely(IS_INTEGER(argv[1]))) return INTEGER_VAL(self operator AS_INTEGER(argv[1])); \
393  return NOTIMPL_VAL(); \
394  } \
395  KRK_Method(int,__r ## name ## __) { \
396  if (likely(IS_INTEGER(argv[1]))) return INTEGER_VAL(AS_INTEGER(argv[1]) operator self); \
397  return NOTIMPL_VAL(); \
398  }
399 
400 #define COMPARE_OP(name,operator) \
401  KRK_Method(int,__ ## name ## __) { \
402  if (likely(IS_INTEGER(argv[1]))) return BOOLEAN_VAL(self operator AS_INTEGER(argv[1])); \
403  else if (likely(IS_FLOATING(argv[1]))) return MAYBE_FLOAT(BOOLEAN_VAL((double)self operator AS_FLOATING(argv[1]))); \
404  return NOTIMPL_VAL(); \
405  }
406 
407 BASIC_BIN_OP(add,+)
408 BASIC_BIN_OP(sub,-)
409 BASIC_BIN_OP(mul,*)
410 INT_ONLY_BIN_OP(or,|)
411 INT_ONLY_BIN_OP(xor,^)
412 INT_ONLY_BIN_OP(and,&)
413 
414 #define DEFER_TO_LONG(name) \
415  extern KrkValue krk_long_coerced_ ## name (krk_integer_type a, krk_integer_type b); \
416  KRK_Method(int,__ ## name ## __) { \
417  if (likely(IS_INTEGER(argv[1]))) return krk_long_coerced_ ## name (self, AS_INTEGER(argv[1])); \
418  return NOTIMPL_VAL(); \
419  } \
420  KRK_Method(int,__r ## name ## __) { \
421  if (likely(IS_INTEGER(argv[1]))) return krk_long_coerced_ ## name (AS_INTEGER(argv[1]), self); \
422  return NOTIMPL_VAL(); \
423  }
424 
425 DEFER_TO_LONG(lshift)
426 DEFER_TO_LONG(rshift)
427 DEFER_TO_LONG(pow)
428 
429 COMPARE_OP(lt, <)
430 COMPARE_OP(gt, >)
431 COMPARE_OP(le, <=)
432 COMPARE_OP(ge, >=)
433 
434 #undef BASIC_BIN_OP
435 #undef INT_ONLY_BIN_OP
436 #undef COMPARE_OP
437 
438 #ifndef KRK_NO_FLOAT
439 KRK_Method(int,__truediv__) {
440  METHOD_TAKES_EXACTLY(1);
441  if (likely(IS_INTEGER(argv[1]))) {
442  krk_integer_type b = AS_INTEGER(argv[1]);
443  if (unlikely(b == 0)) return krk_runtimeError(vm.exceptions->zeroDivisionError, "integer division by zero");
444  return FLOATING_VAL((double)self / (double)b);
445  } else if (likely(IS_FLOATING(argv[1]))) {
446  double b = AS_FLOATING(argv[1]);
447  if (unlikely(b == 0.0)) return krk_runtimeError(vm.exceptions->zeroDivisionError, "float division by zero");
448  return FLOATING_VAL((double)self / b);
449  }
450  return NOTIMPL_VAL();
451 }
452 
453 KRK_Method(int,__rtruediv__) {
454  METHOD_TAKES_EXACTLY(1);
455  if (unlikely(self == 0)) return krk_runtimeError(vm.exceptions->zeroDivisionError, "integer division by zero");
456  else if (likely(IS_INTEGER(argv[1]))) return FLOATING_VAL((double)AS_INTEGER(argv[1]) / (double)self);
457  else if (likely(IS_FLOATING(argv[1]))) return FLOATING_VAL(AS_FLOATING(argv[1]) / (double)self);
458  return NOTIMPL_VAL();
459 }
460 #endif
461 
462 #ifdef __TINYC__
463 #include <math.h>
464 #define __builtin_floor floor
465 #endif
466 
472 static KrkValue _krk_int_div(krk_integer_type a, krk_integer_type b) {
473  if (unlikely(b == 0)) return krk_runtimeError(vm.exceptions->zeroDivisionError, "integer division or modulo by zero");
474  if (a == 0) return INTEGER_VAL(0);
475  int64_t abs_a = a < 0 ? -a : a;
476  int64_t abs_b = b < 0 ? -b : b;
477  if ((a < 0) != (b < 0)) {
478  /* If signs don't match, the result is negative, and rounding down means away from 0... */
479  int64_t res = -1 - (abs_a - 1) / abs_b;
480  return INTEGER_VAL(res);
481  }
482  return INTEGER_VAL((abs_a / abs_b));
483 }
484 
485 static KrkValue _krk_int_mod(krk_integer_type a, krk_integer_type b) {
486  if (unlikely(b == 0)) return krk_runtimeError(vm.exceptions->zeroDivisionError, "integer division or modulo by zero");
487  if (a == 0) return INTEGER_VAL(0);
488  int64_t abs_a = a < 0 ? -a : a;
489  int64_t abs_b = b < 0 ? -b : b;
490  int64_t res;
491  if ((a < 0) != (b < 0)) {
492  /* If quotient would be negative, then remainder is inverted against the divisor. */
493  res = (abs_b - 1 - (abs_a - 1) % abs_b);
494  } else {
495  res = abs_a % abs_b;
496  }
497  /* Negative divisor always yields negative remainder, except when it's 0... */
498  return INTEGER_VAL((b < 0) ? -res : res);
499 
500 }
501 
502 KRK_Method(int,__mod__) {
503  METHOD_TAKES_EXACTLY(1);
504  if (likely(IS_INTEGER(argv[1]))) return _krk_int_mod(self, AS_INTEGER(argv[1]));
505  return NOTIMPL_VAL();
506 }
507 
508 KRK_Method(int,__rmod__) {
509  METHOD_TAKES_EXACTLY(1);
510  if (likely(IS_INTEGER(argv[1]))) return _krk_int_mod(AS_INTEGER(argv[1]), self);
511  return NOTIMPL_VAL();
512 }
513 
514 
515 KRK_Method(int,__floordiv__) {
516  METHOD_TAKES_EXACTLY(1);
517  if (likely(IS_INTEGER(argv[1]))) {
518  return _krk_int_div(self,AS_INTEGER(argv[1]));
519  } else if (likely(IS_FLOATING(argv[1]))) {
520 #ifndef KRK_NO_FLOAT
521  double b = AS_FLOATING(argv[1]);
522  if (unlikely(b == 0.0)) return krk_runtimeError(vm.exceptions->zeroDivisionError, "float division by zero");
523  return FLOATING_VAL(__builtin_floor((double)self / b));
524 #else
525  return krk_runtimeError(vm.exceptions->valueError, "no float support");
526 #endif
527  }
528  return NOTIMPL_VAL();
529 }
530 
531 KRK_Method(int,__rfloordiv__) {
532  METHOD_TAKES_EXACTLY(1);
533  if (unlikely(self == 0)) return krk_runtimeError(vm.exceptions->zeroDivisionError, "integer division by zero");
534  else if (likely(IS_INTEGER(argv[1]))) return _krk_int_div(AS_INTEGER(argv[1]), self);
535  else if (likely(IS_FLOATING(argv[1]))) return MAYBE_FLOAT(FLOATING_VAL(__builtin_floor(AS_FLOATING(argv[1]) / (double)self)));
536  return NOTIMPL_VAL();
537 }
538 
539 KRK_Method(int,__hex__) {
540  METHOD_TAKES_NONE();
541  char tmp[20];
542  unsigned long long val = self < 0 ? -self : self;
543  size_t len = snprintf(tmp, 20, "%s0x%llx", self < 0 ? "-" : "", val);
544  return OBJECT_VAL(krk_copyString(tmp,len));
545 }
546 
547 KRK_Method(int,__oct__) {
548  METHOD_TAKES_NONE();
549  char tmp[20];
550  unsigned long long val = self < 0 ? -self : self;
551  size_t len = snprintf(tmp, 20, "%s0o%llo", self < 0 ? "-" : "", val);
552  return OBJECT_VAL(krk_copyString(tmp,len));
553 }
554 
555 KRK_Method(int,__bin__) {
556  METHOD_TAKES_NONE();
557  unsigned long long val = self;
558  if (self < 0) val = -val;
559 
560  struct StringBuilder sb = {0};
561 
562  if (!val) pushStringBuilder(&sb, '0');
563  while (val) {
564  pushStringBuilder(&sb, (val & 1) ? '1' : '0');
565  val = val >> 1;
566  }
567 
568  pushStringBuilder(&sb, 'b');
569  pushStringBuilder(&sb, '0');
570  if (self< 0) pushStringBuilder(&sb,'-');
571 
572  /* Flip it */
573  for (size_t i = 0; i < sb.length / 2; ++i) {
574  char t = sb.bytes[i];
575  sb.bytes[i] = sb.bytes[sb.length - i - 1];
576  sb.bytes[sb.length - i - 1] = t;
577  }
578 
579  return finishStringBuilder(&sb);
580 }
581 
582 KRK_Method(int,__invert__) {
583  return INTEGER_VAL(~self);
584 }
585 
586 KRK_Method(int,__neg__) {
587  return INTEGER_VAL(-self);
588 }
589 
590 KRK_Method(int,__abs__) {
591  return self < 0 ? INTEGER_VAL(-self) : INTEGER_VAL(self);
592 }
593 
594 KRK_Method(int,__pos__) {
595  return argv[0];
596 }
597 
598 #undef CURRENT_CTYPE
599 #define CURRENT_CTYPE double
600 
601 #define trySlowMethod(name) do { \
602  KrkClass * type = krk_getType(argv[1]); \
603  KrkValue method; \
604  while (type) { \
605  if (krk_tableGet(&type->methods, name, &method)) { \
606  krk_push(method); \
607  krk_push(argv[1]); \
608  return krk_callStack(1); \
609  } \
610  type = type->base; \
611  } \
612 } while (0)
613 
614 #ifndef KRK_NO_FLOAT
615 KRK_StaticMethod(float,__new__) {
616  FUNCTION_TAKES_AT_MOST(2);
617  if (argc < 2) return FLOATING_VAL(0.0);
618  if (IS_FLOATING(argv[1])) return argv[1];
619  if (IS_INTEGER(argv[1])) return FLOATING_VAL(AS_INTEGER(argv[1]));
620  if (IS_BOOLEAN(argv[1])) return FLOATING_VAL(AS_BOOLEAN(argv[1]));
621 
622  trySlowMethod(vm.specialMethodNames[METHOD_FLOAT]);
623 
624  return krk_runtimeError(vm.exceptions->typeError, "%s() argument must be a string or a number, not '%T'", "float", argv[1]);
625 }
626 
627 KRK_Method(float,__int__) { return krk_int_from_float(self); }
628 KRK_Method(float,__float__) { return argv[0]; }
629 
630 extern KrkValue krk_double_to_string(double,unsigned int,char,int,int);
631 KRK_Method(float,__repr__) {
632  return krk_double_to_string(self,16,' ',0,0);
633 }
634 
635 KRK_Method(float,__format__) {
636  char * format_spec;
637  size_t format_spec_length;
638  if (!krk_parseArgs(".s#", (const char*[]){"format_spec"}, &format_spec, &format_spec_length)) return NONE_VAL();
639 
640  struct ParsedFormatSpec opts = {0};
641  const char * spec = krk_parseCommonFormatSpec(&opts, format_spec, format_spec_length);
642  if (!spec) return NONE_VAL();
643 
644  char formatter = 'g';
645  int digits = 16;
646  int forcedigits = opts.alt;
647 
648  switch (*spec) {
649  case 0:
650  case 'g':
651  /* defaults */
652  break;
653 
654  case 'G':
655  formatter = 'G';
656  break;
657 
658  case 'f':
659  case 'F':
660  case 'e':
661  case 'E':
662  digits = 6;
663  formatter = *spec;
664  forcedigits = 1;
665  break;
666 
667  default:
668  return krk_runtimeError(vm.exceptions->valueError,
669  "Unknown format code '%c' for object of type '%s'",
670  *spec,
671  "float");
672  }
673 
674  if (opts.sep) return krk_runtimeError(vm.exceptions->valueError, "unsupported option for float");
675  if (opts.hasPrecision) digits = opts.prec;
676  if (!opts.align) opts.align = '>';
677 
678  KrkValue result = krk_double_to_string(self, digits, formatter, opts.sign == '+', forcedigits);
679  if (!IS_STRING(result) || !opts.width) return result;
680 
681  krk_push(result);
682 
683  /* Calculate how much padding we need to add. */
684  size_t avail = (size_t)opts.width > AS_STRING(result)->length ? (size_t)opts.width - AS_STRING(result)->length : 0;
685 
686  /* If there's no available space for padding, just return the string we already have. */
687  if (!avail) return krk_pop();
688 
689  struct StringBuilder sb = {0};
690  size_t before = 0;
691  size_t after = 0;
692  int hassign = 0;
693  if (opts.align == '<') {
694  after = avail;
695  } else if (opts.align == '>') {
696  before = avail;
697  } else if (opts.align == '^') {
698  after = avail / 2;
699  before = avail - after;
700  } else if (opts.align == '=') {
701  before = avail;
702  if (avail && AS_STRING(result)->length && (AS_CSTRING(result)[0] == '-' || AS_CSTRING(result)[0] == '+')) {
703  krk_pushStringBuilder(&sb, AS_CSTRING(result)[0]);
704  hassign = 1;
705  }
706  }
707 
708  /* Fill in padding with a new string builder. */
709  for (size_t i = 0; i < before; ++i) krk_pushStringBuilderStr(&sb, opts.fill, opts.fillSize);
710  krk_pushStringBuilderStr(&sb, AS_CSTRING(result) + hassign, AS_STRING(result)->length - hassign);
711  for (size_t i = 0; i < after; ++i) krk_pushStringBuilderStr(&sb, opts.fill, opts.fillSize);
712 
713  krk_pop();
714  return krk_finishStringBuilder(&sb);
715 }
716 
717 KRK_Method(float,__eq__) {
718  METHOD_TAKES_EXACTLY(1);
719  if (IS_INTEGER(argv[1])) return BOOLEAN_VAL(self == (double)AS_INTEGER(argv[1]));
720  else if (IS_FLOATING(argv[1])) return BOOLEAN_VAL(self == AS_FLOATING(argv[1]));
721  return NOTIMPL_VAL();
722 }
723 
724 KRK_Method(float,__hash__) {
725  return INTEGER_VAL((uint32_t)self);
726 }
727 
728 KRK_Method(float,__neg__) {
729  return FLOATING_VAL(-self);
730 }
731 
732 KRK_Method(float,__abs__) {
733  return self < 0.0 ? FLOATING_VAL(-self) : INTEGER_VAL(self);
734 }
735 
736 #define BASIC_BIN_OP(name,operator) \
737  KRK_Method(float,__ ## name ## __) { \
738  METHOD_TAKES_EXACTLY(1); \
739  if (likely(IS_FLOATING(argv[1]))) return FLOATING_VAL(self operator AS_FLOATING(argv[1])); \
740  else if (likely(IS_INTEGER(argv[1]))) return FLOATING_VAL(self operator (double)AS_INTEGER(argv[1])); \
741  return NOTIMPL_VAL(); \
742  } \
743  KRK_Method(float,__r ## name ## __) { \
744  METHOD_TAKES_EXACTLY(1); \
745  if (likely(IS_FLOATING(argv[1]))) return FLOATING_VAL(AS_FLOATING(argv[1]) operator self); \
746  else if (likely(IS_INTEGER(argv[1]))) return FLOATING_VAL((double)AS_INTEGER(argv[1]) operator self); \
747  return NOTIMPL_VAL(); \
748  }
749 
750 #define COMPARE_OP(name,operator) \
751  KRK_Method(float,__ ## name ## __) { \
752  METHOD_TAKES_EXACTLY(1); \
753  if (likely(IS_FLOATING(argv[1]))) return BOOLEAN_VAL(self operator AS_FLOATING(argv[1])); \
754  else if (likely(IS_INTEGER(argv[1]))) return BOOLEAN_VAL(self operator (double)AS_INTEGER(argv[1])); \
755  return NOTIMPL_VAL(); \
756  }
757 
758 BASIC_BIN_OP(add,+)
759 BASIC_BIN_OP(sub,-)
760 BASIC_BIN_OP(mul,*)
761 COMPARE_OP(lt, <)
762 COMPARE_OP(gt, >)
763 COMPARE_OP(le, <=)
764 COMPARE_OP(ge, >=)
765 
766 #undef BASIC_BIN_OP
767 #undef COMPARE_OP
768 
769 KRK_Method(float,__truediv__) {
770  METHOD_TAKES_EXACTLY(1);
771  if (likely(IS_FLOATING(argv[1]))) {
772  double b = AS_FLOATING(argv[1]);
773  if (unlikely(b == 0.0)) return krk_runtimeError(vm.exceptions->zeroDivisionError, "float division by zero");
774  return FLOATING_VAL(self / b);
775  } else if (likely(IS_INTEGER(argv[1]))) {
776  krk_integer_type b = AS_INTEGER(argv[1]);
777  if (unlikely(b == 0)) return krk_runtimeError(vm.exceptions->zeroDivisionError, "integer division by zero");
778  return FLOATING_VAL(self / (double)b);
779  }
780  return NOTIMPL_VAL();
781 }
782 
783 KRK_Method(float,__rtruediv__) {
784  METHOD_TAKES_EXACTLY(1);
785  if (unlikely(self == 0.0)) return krk_runtimeError(vm.exceptions->zeroDivisionError, "float division by zero");
786  else if (likely(IS_FLOATING(argv[1]))) return FLOATING_VAL(AS_FLOATING(argv[1]) / self);
787  else if (likely(IS_INTEGER(argv[1]))) return FLOATING_VAL((double)AS_INTEGER(argv[1]) / self);
788  return NOTIMPL_VAL();
789 }
790 
791 KRK_Method(float,__floordiv__) {
792  METHOD_TAKES_EXACTLY(1);
793  if (likely(IS_INTEGER(argv[1]))) {
794  krk_integer_type b = AS_INTEGER(argv[1]);
795  if (unlikely(b == 0)) return krk_runtimeError(vm.exceptions->zeroDivisionError, "integer division by zero");
796  return FLOATING_VAL(__builtin_floor(self / (double)b));
797  } else if (IS_FLOATING(argv[1])) {
798  double b = AS_FLOATING(argv[1]);
799  if (unlikely(b == 0.0)) return krk_runtimeError(vm.exceptions->zeroDivisionError, "float division by zero");
800  return FLOATING_VAL(__builtin_floor(self / b));
801  }
802  return NOTIMPL_VAL();
803 }
804 
805 KRK_Method(float,__rfloordiv__) {
806  METHOD_TAKES_EXACTLY(1);
807  if (unlikely(self == 0.0)) return krk_runtimeError(vm.exceptions->zeroDivisionError, "float division by zero");
808  else if (likely(IS_INTEGER(argv[1]))) return FLOATING_VAL((double)AS_INTEGER(argv[1]) / self);
809  else if (IS_FLOATING(argv[1])) return FLOATING_VAL(__builtin_floor(AS_FLOATING(argv[1]) / self));
810  return NOTIMPL_VAL();
811 }
812 
813 KRK_Method(float,__pos__) {
814  return argv[0];
815 }
816 
817 extern KrkValue krk_float_to_fraction(double d);
818 KRK_Method(float,as_integer_ratio) {
819  return krk_float_to_fraction(self);
820 }
821 #endif
822 
823 #undef CURRENT_CTYPE
824 #define CURRENT_CTYPE krk_integer_type
825 
826 KRK_StaticMethod(bool,__new__) {
827  FUNCTION_TAKES_AT_MOST(2);
828  if (argc < 2) return BOOLEAN_VAL(0);
829  return BOOLEAN_VAL(!krk_isFalsey(argv[1]));
830 }
831 
832 KRK_Method(bool,__repr__) {
833  return OBJECT_VAL((self ? S("True") : S("False")));
834 }
835 
836 KRK_Method(bool,__format__) {
837  METHOD_TAKES_EXACTLY(1);
838  CHECK_ARG(1,str,KrkString*,format_spec);
839 
840  if (!format_spec->length) {
841  return FUNC_NAME(bool,__repr__)(argc,argv,hasKw);
842  } else {
843  return FUNC_NAME(int,__format__)(argc,argv,hasKw);
844  }
845 }
846 
847 KRK_StaticMethod(NoneType,__new__) {
848  if (argc > 1) return krk_runtimeError(vm.exceptions->argumentError, "%s takes no arguments", "NoneType");
849  return NONE_VAL();
850 }
851 
852 KRK_Method(NoneType,__repr__) {
853  return OBJECT_VAL(S("None"));
854 }
855 
856 KRK_Method(NoneType,__hash__) {
857  return INTEGER_VAL((uint32_t)AS_INTEGER(argv[0]));
858 }
859 
860 KRK_Method(NoneType,__eq__) {
861  METHOD_TAKES_EXACTLY(1);
862  if (IS_NONE(argv[1])) return BOOLEAN_VAL(1);
863  return NOTIMPL_VAL();
864 }
865 
866 #define IS_NotImplementedType(o) IS_NOTIMPL(o)
867 #define AS_NotImplementedType(o) (1)
868 
869 KRK_StaticMethod(NotImplementedType,__new__) {
870  if (argc > 1) return krk_runtimeError(vm.exceptions->argumentError, "%s takes no arguments", "NotImplementedType");
871  return NOTIMPL_VAL();
872 }
873 
874 KRK_Method(NotImplementedType,__repr__) {
875  return OBJECT_VAL(S("NotImplemented"));
876 }
877 
878 KRK_Method(NotImplementedType,__hash__) {
879  return INTEGER_VAL(0);
880 }
881 
882 KRK_Method(NotImplementedType,__eq__) {
883  METHOD_TAKES_EXACTLY(1);
884  if (IS_NOTIMPL(argv[1])) return BOOLEAN_VAL(1);
885  return NOTIMPL_VAL();
886 }
887 
888 #undef BIND_METHOD
889 #undef BIND_STATICMETHOD
890 /* These class names conflict with C types, so we need to cheat a bit */
891 #define BIND_METHOD(klass,method) do { krk_defineNative(& _ ## klass->methods, #method, _ ## klass ## _ ## method); } while (0)
892 #define BIND_STATICMETHOD(klass,method) do { krk_defineNativeStaticMethod(& _ ## klass->methods, #method, _ ## klass ## _ ## method); } while (0)
893 #define BIND_TRIPLET(klass,name) \
894  BIND_METHOD(klass,__ ## name ## __); \
895  BIND_METHOD(klass,__r ## name ## __); \
896  krk_defineNative(&_ ## klass->methods,"__i" #name "__",_ ## klass ## ___ ## name ## __);
897 _noexport
898 void _createAndBind_numericClasses(void) {
899  KrkClass * _int = ADD_BASE_CLASS(vm.baseClasses->intClass, "int", vm.baseClasses->objectClass);
900  _int->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
901  _int->allocSize = 0;
902  BIND_STATICMETHOD(int,__new__);
903  BIND_METHOD(int,__repr__);
904  BIND_METHOD(int,__int__);
905  BIND_METHOD(int,__chr__);
906  BIND_METHOD(int,__eq__);
907  BIND_METHOD(int,__hash__);
908  BIND_METHOD(int,__format__);
909 
910  BIND_TRIPLET(int,add);
911  BIND_TRIPLET(int,sub);
912  BIND_TRIPLET(int,mul);
913  BIND_TRIPLET(int,or);
914  BIND_TRIPLET(int,xor);
915  BIND_TRIPLET(int,and);
916  BIND_TRIPLET(int,lshift);
917  BIND_TRIPLET(int,rshift);
918  BIND_TRIPLET(int,mod);
919  BIND_TRIPLET(int,floordiv);
920  BIND_TRIPLET(int,pow);
921 
922 #ifndef KRK_NO_FLOAT
923  BIND_METHOD(int,__float__);
924  BIND_TRIPLET(int,truediv);
925 #endif
926 
927  BIND_METHOD(int,__lt__);
928  BIND_METHOD(int,__gt__);
929  BIND_METHOD(int,__le__);
930  BIND_METHOD(int,__ge__);
931 
932  BIND_METHOD(int,__hex__);
933  BIND_METHOD(int,__oct__);
934  BIND_METHOD(int,__bin__);
935  BIND_METHOD(int,__invert__);
936  BIND_METHOD(int,__neg__);
937  BIND_METHOD(int,__abs__);
938  BIND_METHOD(int,__pos__);
939 
940  krk_finalizeClass(_int);
941  KRK_DOC(_int, "Convert a number or string type to an integer representation.");
942 
943  KrkClass * _float = ADD_BASE_CLASS(vm.baseClasses->floatClass, "float", vm.baseClasses->objectClass);
944  _float->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
945  _float->allocSize = 0;
946 #ifndef KRK_NO_FLOAT
947  BIND_STATICMETHOD(float,__new__);
948  BIND_METHOD(float,__int__);
949  BIND_METHOD(float,__float__);
950  BIND_METHOD(float,__repr__);
951  BIND_METHOD(float,__eq__);
952  BIND_METHOD(float,__hash__);
953  BIND_TRIPLET(float,add);
954  BIND_TRIPLET(float,sub);
955  BIND_TRIPLET(float,mul);
956  BIND_TRIPLET(float,truediv);
957  BIND_TRIPLET(float,floordiv);
958  BIND_METHOD(float,__lt__);
959  BIND_METHOD(float,__gt__);
960  BIND_METHOD(float,__le__);
961  BIND_METHOD(float,__ge__);
962  BIND_METHOD(float,__neg__);
963  BIND_METHOD(float,__abs__);
964  BIND_METHOD(float,__pos__);
965  BIND_METHOD(float,__format__);
966  BIND_METHOD(float,as_integer_ratio);
967 #endif
968  krk_finalizeClass(_float);
969  KRK_DOC(_float, "Convert a number or string type to a float representation.");
970 
971  KrkClass * _bool = ADD_BASE_CLASS(vm.baseClasses->boolClass, "bool", vm.baseClasses->intClass);
972  _bool->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
973  BIND_STATICMETHOD(bool,__new__);
974  BIND_METHOD(bool,__repr__);
975  BIND_METHOD(bool,__format__);
976  krk_finalizeClass(_bool);
977  KRK_DOC(_bool, "Returns False if the argument is 'falsey', otherwise True.");
978 
979  KrkClass * _NoneType = ADD_BASE_CLASS(vm.baseClasses->noneTypeClass, "NoneType", vm.baseClasses->objectClass);
980  _NoneType->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
981  _NoneType->allocSize = 0;
982  BIND_STATICMETHOD(NoneType, __new__);
983  BIND_METHOD(NoneType, __repr__);
984  BIND_METHOD(NoneType, __hash__);
985  BIND_METHOD(NoneType, __eq__);
986  krk_finalizeClass(_NoneType);
987 
988  KrkClass * _NotImplementedType = ADD_BASE_CLASS(vm.baseClasses->notImplClass, "NotImplementedType", vm.baseClasses->objectClass);
989  _NotImplementedType->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
990  _NotImplementedType->allocSize = 0;
991  BIND_STATICMETHOD(NotImplementedType, __new__);
992  BIND_METHOD(NotImplementedType, __repr__);
993  BIND_METHOD(NotImplementedType, __hash__);
994  BIND_METHOD(NotImplementedType, __eq__);
995  krk_finalizeClass(_NotImplementedType);
996 
997  krk_attachNamedValue(&vm.builtins->fields, "NotImplemented", NOTIMPL_VAL());
998 }
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_double_to_string(double a, unsigned int digits, char formatter, int plus, int forcedigits)
Convert a double to a KrkString.
Definition: obj_long.c:2562
KrkValue krk_float_to_fraction(double d)
Convert a double to a tuple of two longs.
Definition: obj_long.c:2998
Internal header.
Type object.
Definition: object.h:215
size_t allocSize
Size to allocate when creating instances of this class.
Definition: object.h:222
KrkObj obj
Base.
Definition: object.h:216
void krk_finalizeClass(KrkClass *_class)
Finalize a class by collecting pointers to core methods.
Definition: vm.c:189
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
KrkString * krk_copyString(const char *chars, size_t length)
Obtain a string object representation of the given C string.
Definition: object.c:224
char * chars
UTF8 canonical data.
Definition: object.h:97
size_t length
String length in bytes.
Definition: object.h:95
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
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
Stack reference or primative value.
const char * krk_typeName(KrkValue value)
Get the name of the type of a value.
Definition: vm.c:984
int krk_isInstanceOf(KrkValue obj, const KrkClass *type)
Determine if a class is an instance or subclass of a given type.
Definition: vm.c:282
int krk_isFalsey(KrkValue value)
Determine the truth of a value.
Definition: vm.c:821
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_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.
#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_push(KrkValue value)
Push a stack value.
Definition: vm.c:118