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