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("slice(...)");
122  ((KrkObj*)self)->flags |= KRK_OBJ_FLAGS_IN_REPR;
123  struct StringBuilder sb = {0};
124  pushStringBuilderStr(&sb,"slice(",6);
125 
126  KrkClass * type;
127  KrkValue result;
128 
129  /* start */
130  type = krk_getType(self->start);
131  krk_push(self->start);
132  result = krk_callDirect(type->_reprer, 1);
133  if (IS_STRING(result)) pushStringBuilderStr(&sb, AS_STRING(result)->chars, AS_STRING(result)->length);
134  pushStringBuilderStr(&sb,", ",2);
135 
136  /* end */
137  type = krk_getType(self->end);
138  krk_push(self->end);
139  result = krk_callDirect(type->_reprer, 1);
140  if (IS_STRING(result)) pushStringBuilderStr(&sb, AS_STRING(result)->chars, AS_STRING(result)->length);
141  pushStringBuilderStr(&sb,", ",2);
142 
143  /* step */
144  type = krk_getType(self->step);
145  krk_push(self->step);
146  result = krk_callDirect(type->_reprer, 1);
147  if (IS_STRING(result)) pushStringBuilderStr(&sb, AS_STRING(result)->chars, AS_STRING(result)->length);
148 
149  pushStringBuilder(&sb,')');
150  ((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
151  return finishStringBuilder(&sb);
152 }
153 
154 KRK_Method(slice,start) {
155  ATTRIBUTE_NOT_ASSIGNABLE();
156  return self->start;
157 }
158 
159 KRK_Method(slice,end) {
160  ATTRIBUTE_NOT_ASSIGNABLE();
161  return self->end;
162 }
163 
164 KRK_Method(slice,step) {
165  ATTRIBUTE_NOT_ASSIGNABLE();
166  return self->step;
167 }
168 
169 _noexport
170 void _createAndBind_sliceClass(void) {
171  KrkClass * slice = ADD_BASE_CLASS(vm.baseClasses->sliceClass, "slice", vm.baseClasses->objectClass);
172  slice->allocSize = sizeof(struct KrkSlice);
173  slice->_ongcscan = _slice_gcscan;
174  slice->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT;
175  BIND_METHOD(slice,__init__);
176  BIND_METHOD(slice,__repr__);
177  BIND_PROP(slice,start);
178  BIND_PROP(slice,end);
179  BIND_PROP(slice,step);
180  krk_defineNative(&slice->methods, "__str__", FUNC_NAME(slice,__repr__));
181  krk_attachNamedValue(&slice->methods, "__hash__", NONE_VAL());
182  krk_finalizeClass(slice);
183 }
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.
void krk_markValue(KrkValue value)
During a GC scan cycle, mark a value as used.
Definition: memory.c:329
Type object.
Definition: object.h:189
KrkCleanupCallback _ongcscan
C function to call when the garbage collector visits an instance of this class in the scan phase.
Definition: object.h:197
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.
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
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
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
Stack reference or primative value.
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.
Definitions for primitive stack references.
Core API for the bytecode virtual machine.
#define vm
Convenience macro for namespacing.
Definition: vm.h:267
KrkValue krk_pop(void)
Pop the top of the stack.
Definition: vm.c:170
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