obj_slice.c
1 #include <string.h>
2 #include <limits.h>
3 #include <kuroko/vm.h>
4 #include <kuroko/value.h>
5 #include <kuroko/memory.h>
6 #include <kuroko/util.h>
7 
8 static void _slice_gcscan(KrkInstance * self) {
9  krk_markValue(((struct KrkSlice*)self)->start);
10  krk_markValue(((struct KrkSlice*)self)->end);
11  krk_markValue(((struct KrkSlice*)self)->step);
12 }
13 
14 KrkValue krk_slice_of(int argc, const KrkValue argv[], int hasKw) {
15  KrkValue outSlice = OBJECT_VAL(krk_newInstance(vm.baseClasses->sliceClass));
16  krk_push(outSlice);
17 
18  AS_slice(outSlice)->start = (argc > 0) ? argv[0] : NONE_VAL();
19  AS_slice(outSlice)->end = (argc > 1) ? argv[1] : NONE_VAL();
20  AS_slice(outSlice)->step = (argc > 2) ? argv[2] : NONE_VAL();
21 
22  return krk_pop();
23 }
24 
25 static inline krk_integer_type _wrap(krk_integer_type count, krk_integer_type val) {
26  if (val < 0) val += count;
27  if (val < 0) val = 0;
28  if (val > count) val = count;
29  return val;
30 }
31 
32 static inline krk_integer_type _wrapn(krk_integer_type count, krk_integer_type val) {
33  if (val < 0) val += count;
34  if (val < -1) val = -1;
35  if (val > count) val = count;
36  return val;
37 }
38 
39 int krk_extractSlicer(const char * _method_name, KrkValue slicerVal, krk_integer_type count, krk_integer_type *start, krk_integer_type *end, krk_integer_type *step) {
40  if (!(IS_slice(slicerVal))) {
41  TYPE_ERROR(slice, slicerVal);
42  return 1;
43  }
44 
45  struct KrkSlice * slicer = AS_slice(slicerVal);
46 
47  KrkValue _start = slicer->start;
48  KrkValue _end = slicer->end;
49  KrkValue _step = slicer->step;
50 
51  if (!(IS_INTEGER(_start) || IS_NONE(_start))) {
52  TYPE_ERROR(int or None, _start);
53  return 1;
54  }
55 
56  if (!(IS_INTEGER(_end) || IS_NONE(_end))) {
57  TYPE_ERROR(int or None, _end);
58  return 1;
59  }
60 
61  if (!(IS_INTEGER(_step) || IS_NONE(_step))) {
62  TYPE_ERROR(int or None, _step);
63  }
64 
65  if (count == 0) {
66  *start = 0;
67  *end = 0;
68  *step = 1;
69  return 0;
70  }
71 
72  /* First off, the step */
73  *step = IS_NONE(_step) ? 1 : AS_INTEGER(_step);
74 
75  if (*step == 0) {
76  krk_runtimeError(vm.exceptions->valueError, "invalid 0 step");
77  return 1;
78  }
79 
80  if (*step > 0) {
81  /* Normal step bounds */
82  *start = _wrap(count, IS_NONE(_start) ? 0 : AS_INTEGER(_start));
83  *end = _wrap(count, IS_NONE(_end) ? count : AS_INTEGER(_end));
84  if (*end < *start) *end = *start;
85  } else {
86  *start = IS_NONE(_start) ? (count-1) : _wrap(count, AS_INTEGER(_start));
87  if (*start >= count) *start = count -1;
88  *end = IS_NONE(_end) ? -1 : _wrapn(count, AS_INTEGER(_end));
89  if (*end > *start) *end = *start;
90  }
91 
92  return 0;
93 }
94 
95 #define CURRENT_CTYPE struct KrkSlice *
96 #define CURRENT_NAME self
97 
98 KRK_Method(slice,__init__) {
99  METHOD_TAKES_AT_LEAST(1);
100  METHOD_TAKES_AT_MOST(3);
101 
102  if (argc == 2) {
103  self->start = NONE_VAL();
104  self->end = argv[1];
105  self->step = NONE_VAL();
106  } else {
107  self->start = argv[1];
108  self->end = argv[2];
109  if (argc > 3) {
110  self->step = argv[3];
111  } else {
112  self->step = NONE_VAL();
113  }
114  }
115 
116  return NONE_VAL();
117 }
118 
119 KRK_Method(slice,__repr__) {
120  METHOD_TAKES_NONE();
121  if (((KrkObj*)self)->flags & KRK_OBJ_FLAGS_IN_REPR) return OBJECT_VAL(S("slice(...)"));
122  ((KrkObj*)self)->flags |= KRK_OBJ_FLAGS_IN_REPR;
123  struct StringBuilder sb = {0};
124  pushStringBuilderStr(&sb,"slice(",6);
125  /* start */
126  if (!krk_pushStringBuilderFormat(&sb, "%R", self->start)) goto _error;
127  pushStringBuilderStr(&sb,", ",2);
128  if (!krk_pushStringBuilderFormat(&sb, "%R", self->end)) goto _error;
129  pushStringBuilderStr(&sb,", ",2);
130  if (!krk_pushStringBuilderFormat(&sb, "%R", self->step)) goto _error;
131  pushStringBuilder(&sb,')');
132  ((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
133  return finishStringBuilder(&sb);
134 
135 _error:
136  ((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
138  return NONE_VAL();
139 }
140 
141 KRK_Method(slice,start) {
142  ATTRIBUTE_NOT_ASSIGNABLE();
143  return self->start;
144 }
145 
146 KRK_Method(slice,end) {
147  ATTRIBUTE_NOT_ASSIGNABLE();
148  return self->end;
149 }
150 
151 KRK_Method(slice,step) {
152  ATTRIBUTE_NOT_ASSIGNABLE();
153  return self->step;
154 }
155 
156 #undef CURRENT_CTYPE
157 #define CURRENT_CTYPE KrkInstance *
158 #define IS_ellipsis(o) (krk_isInstanceOf(o,KRK_BASE_CLASS(ellipsis)))
159 #define AS_ellipsis(o) ((KrkInstance*)AS_INSTANCE(o))
160 
161 KRK_StaticMethod(ellipsis,__new__) {
162  KrkClass * _class = NULL;
163  if (!krk_parseArgs("O!", (const char*[]){"cls"}, KRK_BASE_CLASS(type), &_class)) return NONE_VAL();
164  if (!krk_isSubClass(_class, KRK_BASE_CLASS(ellipsis))) {
165  return krk_runtimeError(vm.exceptions->typeError, "%S is not a subclass of %S", _class->name, KRK_BASE_CLASS(ellipsis)->name);
166  }
167 
168  KrkValue out;
169  if (!krk_tableGet_fast(&vm.builtins->fields, S("Ellipsis"), &out)) return krk_runtimeError(vm.exceptions->typeError, "Ellipsis is missing");
170  return out;
171 }
172 
173 KRK_Method(ellipsis,__repr__) {
174  return OBJECT_VAL(S("Ellipsis"));
175 }
176 
177 _noexport
178 void _createAndBind_sliceClass(void) {
179  KrkClass * slice = ADD_BASE_CLASS(KRK_BASE_CLASS(slice), "slice", KRK_BASE_CLASS(object));
180  slice->allocSize = sizeof(struct KrkSlice);
181  slice->_ongcscan = _slice_gcscan;
182  slice->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
183  BIND_METHOD(slice,__init__);
184  BIND_METHOD(slice,__repr__);
185  BIND_PROP(slice,start);
186  BIND_PROP(slice,end);
187  BIND_PROP(slice,step);
188  krk_attachNamedValue(&slice->methods, "__hash__", NONE_VAL());
189  krk_finalizeClass(slice);
190 
191  KrkClass * ellipsis = ADD_BASE_CLASS(KRK_BASE_CLASS(ellipsis), "ellipsis", KRK_BASE_CLASS(object));
192  krk_attachNamedObject(&vm.builtins->fields, "Ellipsis", (KrkObj*)krk_newInstance(ellipsis));
193  ellipsis->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
194  BIND_STATICMETHOD(ellipsis,__new__);
195  BIND_METHOD(ellipsis,__repr__);
196  krk_finalizeClass(ellipsis);
197 
198 }
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.
void krk_markValue(KrkValue value)
During a GC scan cycle, mark a value as used.
Definition: memory.c:334
Type object.
Definition: object.h:215
KrkCleanupCallback _ongcscan
C function to call when the garbage collector visits an instance of this class in the scan phase.
Definition: object.h:223
KrkString * name
Name of the class.
Definition: object.h:219
size_t allocSize
Size to allocate when creating instances of this class.
Definition: object.h:222
KrkObj obj
Base.
Definition: object.h:216
KrkTable methods
General attributes table.
Definition: object.h:218
void krk_finalizeClass(KrkClass *_class)
Finalize a class by collecting pointers to core methods.
Definition: vm.c:189
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
The most basic object type.
Definition: object.h:41
uint16_t flags
General object flags, mostly related to garbage collection.
Definition: object.h:43
KrkValue krk_slice_of(int argc, const KrkValue argv[], int hasKw)
Create a slice object.
Definition: obj_slice.c:14
void krk_attachNamedObject(KrkTable *table, const char name[], KrkObj *obj)
Attach an object to an attribute table.
Definition: vm.c:808
void krk_attachNamedValue(KrkTable *table, const char name[], KrkValue obj)
Attach a value to an attribute table.
Definition: vm.c:794
int krk_tableGet_fast(KrkTable *table, struct KrkString *str, KrkValue *value)
Obtain the value associated with a string key in a table.
Definition: table.c:219
Stack reference or primative value.
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_discardStringBuilder(struct StringBuilder *sb)
Discard the contents of a string builder.
Definition: obj_str.c:1123
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