obj_range.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 
13 struct Range {
14  KrkInstance inst;
15  krk_integer_type min;
16  krk_integer_type max;
17  krk_integer_type step;
18 };
19 #define IS_range(o) (krk_isInstanceOf(o,KRK_BASE_CLASS(range)))
20 #define AS_range(o) ((struct Range*)AS_OBJECT(o))
21 
22 struct RangeIterator {
23  KrkInstance inst;
24  krk_integer_type i;
25  krk_integer_type max;
26  krk_integer_type step;
27 };
28 #define IS_rangeiterator(o) (krk_isInstanceOf(o,KRK_BASE_CLASS(rangeiterator)))
29 #define AS_rangeiterator(o) ((struct RangeIterator*)AS_OBJECT(o))
30 
31 FUNC_SIG(rangeiterator,__init__);
32 
33 #define CURRENT_NAME self
34 #define CURRENT_CTYPE struct Range *
35 
36 KRK_Method(range,__init__) {
37  METHOD_TAKES_AT_LEAST(1);
38  METHOD_TAKES_AT_MOST(3);
39  self->min = 0;
40  self->step = 1;
41  if (argc == 2) {
42  CHECK_ARG(1,int,krk_integer_type,_max);
43  self->max = _max;
44  } else {
45  CHECK_ARG(1,int,krk_integer_type,_min);
46  CHECK_ARG(2,int,krk_integer_type,_max);
47  self->min = _min;
48  self->max = _max;
49  if (argc == 4) {
50  CHECK_ARG(3,int,krk_integer_type,_step);
51  if (_step == 0) {
52  return krk_runtimeError(vm.exceptions->valueError, "range() arg 3 must not be zero");
53  }
54  self->step = _step;
55  }
56  }
57  return NONE_VAL();
58 }
59 
60 KRK_Method(range,__repr__) {
61  METHOD_TAKES_NONE();
62  struct StringBuilder sb = {0};
63  krk_pushStringBuilderFormat(&sb, "range(%zd,%zd", (ssize_t)self->min, (ssize_t)self->max);
64  if (self->step != 1) krk_pushStringBuilderFormat(&sb, ",%zd", (ssize_t)self->step);
65  krk_pushStringBuilder(&sb,')');
66  return krk_finishStringBuilder(&sb);
67 }
68 
69 KRK_Method(range,__iter__) {
70  KrkInstance * output = krk_newInstance(KRK_BASE_CLASS(rangeiterator));
71  krk_integer_type min = self->min;
72  krk_integer_type max = self->max;
73  krk_integer_type step = self->step;
74 
75  krk_push(OBJECT_VAL(output));
76  FUNC_NAME(rangeiterator,__init__)(4, (KrkValue[]){krk_peek(0), INTEGER_VAL(min), INTEGER_VAL(max), INTEGER_VAL(step)},0);
77  krk_pop();
78 
79  return OBJECT_VAL(output);
80 }
81 
82 KRK_Method(range,__contains__) {
83  int i;
84  if (!krk_parseArgs(".i", (const char*[]){"i"}, &i)) return NONE_VAL();
85  if (self->step == 1) return BOOLEAN_VAL(i >= self->min && i < self->max);
86  if (self->step == -1) return BOOLEAN_VAL(i <= self->min && i > self->max);
87  if (self->step > 0) {
88  if (i >= self->max || i < self->min) return BOOLEAN_VAL(0);
89  if ((i - self->min) % self->step) return BOOLEAN_VAL(0);
90  return BOOLEAN_VAL(1);
91  } else {
92  if (i <= self->max || i > self->min) return BOOLEAN_VAL(0);
93  if ((i - self->min) % -self->step) return BOOLEAN_VAL(0);
94  return BOOLEAN_VAL(1);
95  }
96 }
97 
98 #undef CURRENT_CTYPE
99 #define CURRENT_CTYPE struct RangeIterator *
100 
101 KRK_Method(rangeiterator,__init__) {
102  METHOD_TAKES_EXACTLY(3);
103  CHECK_ARG(1,int,krk_integer_type,i);
104  CHECK_ARG(2,int,krk_integer_type,max);
105  CHECK_ARG(3,int,krk_integer_type,step);
106  self->i = i;
107  self->max = max;
108  self->step = step;
109  return NONE_VAL();
110 }
111 
112 KRK_Method(rangeiterator,__call__) {
113  METHOD_TAKES_NONE();
114  krk_integer_type i = self->i;
115  if (self->step > 0 ? (i >= self->max) : (i <= self->max)) {
116  return argv[0];
117  } else {
118  self->i = i + self->step;
119  return INTEGER_VAL(i);
120  }
121 }
122 
123 _noexport
124 void _createAndBind_rangeClass(void) {
125  KrkClass * range = ADD_BASE_CLASS(vm.baseClasses->rangeClass, "range", vm.baseClasses->objectClass);
126  range->allocSize = sizeof(struct Range);
127  range->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
128  KRK_DOC(BIND_METHOD(range,__init__),
129  "@brief Create an iterable that produces sequential numeric values.\n"
130  "@arguments [min,] max, [step]\n\n"
131  "With one argument, iteration will start at @c 0 and continue to @p max, exclusive. "
132  "With two arguments, iteration starts at @p min and continues to @p max, exclusive. "
133  "With three arguments, a @p step may also be included.");
134  BIND_METHOD(range,__iter__);
135  BIND_METHOD(range,__repr__);
136  BIND_METHOD(range,__contains__);
137  KRK_DOC(range, "@brief Iterable object that produces sequential numeric values.");
138  krk_finalizeClass(range);
139 
140  KrkClass * rangeiterator = ADD_BASE_CLASS(vm.baseClasses->rangeiteratorClass, "rangeiterator", vm.baseClasses->objectClass);
141  rangeiterator->allocSize = sizeof(struct RangeIterator);
142  rangeiterator->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
143  BIND_METHOD(rangeiterator,__init__);
144  BIND_METHOD(rangeiterator,__call__);
145  krk_finalizeClass(rangeiterator);
146 }
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.
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
An object of a class.
Definition: object.h:281
KrkInstance * krk_newInstance(KrkClass *_class)
Create a new instance of the given class.
Definition: object.c:343
uint16_t flags
General object flags, mostly related to garbage collection.
Definition: object.h:43
Stack reference or primative value.
range object.
Definition: obj_range.c:13
Inline flexible string array.
Definition: util.h:162
Utilities for creating native bindings.
#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.
#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
KrkValue krk_peek(int distance)
Peek down from the top of the stack.
Definition: vm.c:139