14 #define AS_bytes(o) AS_BYTES(o)
15 #define CURRENT_CTYPE KrkBytes *
16 #define CURRENT_NAME self
19 #define IS_bytes(o) (IS_BYTES(o) || krk_isInstanceOf(o, vm.baseClasses->bytesClass))
21 static int _bytes_callback(
void * context,
const KrkValue * values,
size_t count) {
23 for (
size_t i = 0; i < count; ++i) {
24 if (!IS_INTEGER(values[i])) {
28 if (AS_INTEGER(values[i]) < 0 || AS_INTEGER(values[i]) > 255) {
32 pushStringBuilder(sb, AS_INTEGER(values[i]));
37 KRK_StaticMethod(bytes,__new__) {
39 METHOD_TAKES_AT_MOST(1);
41 if (IS_bytearray(argv[1])) {
43 AS_BYTES(AS_bytearray(argv[1])->actual)->length,
44 AS_BYTES(AS_bytearray(argv[1])->actual)->bytes));
45 }
else if (IS_STRING(argv[1])) {
46 return OBJECT_VAL(
krk_newBytes(AS_STRING(argv[1])->length, (uint8_t*)AS_CSTRING(argv[1])));
47 }
else if (IS_INTEGER(argv[1])) {
48 if (AS_INTEGER(argv[1]) < 0)
return krk_runtimeError(
vm.exceptions->valueError,
"negative count");
49 return OBJECT_VAL(
krk_newBytes(AS_INTEGER(argv[1]),NULL));
53 return finishStringBuilderBytes(&sb);
58 #define IS_bytes(o) IS_BYTES(o)
60 KRK_Method(bytes,__hash__) {
65 for (
size_t i = 0; i <
self->length; ++i) {
66 krk_hash_advance(hash,self->bytes[i]);
68 return INTEGER_VAL(hash);
72 KRK_Method(bytes,__eq__) {
73 if (!IS_BYTES(argv[1]))
return BOOLEAN_VAL(0);
75 if (self->length != them->
length)
return BOOLEAN_VAL(0);
76 if (self->obj.hash != them->
obj.
hash)
return BOOLEAN_VAL(0);
77 for (
size_t i = 0; i <
self->length; ++i) {
78 if (self->bytes[i] != them->
bytes[i])
return BOOLEAN_VAL(0);
80 return BOOLEAN_VAL(1);
83 #define AT_END() (self->length == 0 || i == self->length - 1)
85 KRK_Method(bytes,__repr__) {
88 pushStringBuilder(&sb,
'b');
89 pushStringBuilder(&sb,
'\'');
91 for (
size_t i = 0; i < AS_BYTES(argv[0])->length; ++i) {
92 uint8_t ch = AS_BYTES(argv[0])->bytes[i];
94 case '\\': pushStringBuilder(&sb,
'\\'); pushStringBuilder(&sb,
'\\');
break;
95 case '\'': pushStringBuilder(&sb,
'\\'); pushStringBuilder(&sb,
'\'');
break;
96 case '\a': pushStringBuilder(&sb,
'\\'); pushStringBuilder(&sb,
'a');
break;
97 case '\b': pushStringBuilder(&sb,
'\\'); pushStringBuilder(&sb,
'b');
break;
98 case '\f': pushStringBuilder(&sb,
'\\'); pushStringBuilder(&sb,
'f');
break;
99 case '\n': pushStringBuilder(&sb,
'\\'); pushStringBuilder(&sb,
'n');
break;
100 case '\r': pushStringBuilder(&sb,
'\\'); pushStringBuilder(&sb,
'r');
break;
101 case '\t': pushStringBuilder(&sb,
'\\'); pushStringBuilder(&sb,
't');
break;
102 case '\v': pushStringBuilder(&sb,
'\\'); pushStringBuilder(&sb,
'v');
break;
104 if (ch < ' ' || ch >= 0x7F) {
105 pushStringBuilder(&sb,
'\\');
106 pushStringBuilder(&sb,
'x');
108 snprintf(hex,3,
"%02x", ch);
109 pushStringBuilder(&sb, hex[0]);
110 pushStringBuilder(&sb, hex[1]);
112 pushStringBuilder(&sb, ch);
119 pushStringBuilder(&sb,
'\'');
121 return finishStringBuilder(&sb);
124 KRK_Method(bytes,__getitem__) {
125 METHOD_TAKES_EXACTLY(1);
127 if (IS_INTEGER(argv[1])) {
128 CHECK_ARG(1,
int,krk_integer_type,asInt);
130 if (asInt < 0) asInt += (long)self->length;
131 if (asInt < 0 || asInt >= (
long)
self->length) {
132 return krk_runtimeError(
vm.exceptions->indexError,
"bytes index out of range: %d", (
int)asInt);
135 return INTEGER_VAL(self->bytes[asInt]);
137 }
else if (IS_slice(argv[1])) {
138 KRK_SLICER(argv[1],self->length) {
143 krk_integer_type len = end - start;
144 return OBJECT_VAL(
krk_newBytes(len, &self->bytes[start]));
147 krk_integer_type i = start;
148 while ((step < 0) ? (i > end) : (i < end)) {
149 pushStringBuilder(&sb, self->bytes[i]);
152 return finishStringBuilderBytes(&sb);
155 return TYPE_ERROR(
int or slice, argv[1]);
159 KRK_Method(bytes,__len__) {
160 return INTEGER_VAL(AS_BYTES(argv[0])->length);
163 KRK_Method(bytes,__contains__) {
164 METHOD_TAKES_EXACTLY(1);
166 if (IS_BYTES(argv[1])) {
167 return krk_runtimeError(
vm.exceptions->notImplementedError,
"not implemented: bytes.__contains__(bytes)");
170 if (!IS_INTEGER(argv[1])) {
171 return TYPE_ERROR(
int,argv[1]);
174 krk_integer_type val = AS_INTEGER(argv[1]);
175 if (val < 0 || val > 255) {
179 for (
size_t i = 0; i <
self->length; ++i) {
180 if (self->bytes[i] == val)
return BOOLEAN_VAL(1);
183 return BOOLEAN_VAL(0);
186 KRK_Method(bytes,decode) {
188 return OBJECT_VAL(
krk_copyString((
char*)AS_BYTES(argv[0])->bytes, AS_BYTES(argv[0])->length));
197 static int _bytes_join_callback(
void * context,
const KrkValue * values,
size_t count) {
200 for (
size_t i = 0; i < count; ++i) {
201 if (!IS_BYTES(values[i])) {
203 "join",
"bytes", values[i]);
207 if (_context->isFirst) {
208 _context->isFirst = 0;
210 pushStringBuilderStr(_context->sb, (
char*)_context->self->
bytes, _context->self->
length);
212 pushStringBuilderStr(_context->sb, (
char*)AS_BYTES(values[i])->bytes, AS_BYTES(values[i])->length);
218 KRK_Method(bytes,join) {
219 METHOD_TAKES_EXACTLY(1);
226 discardStringBuilder(&sb);
230 return finishStringBuilderBytes(&sb);
233 KRK_Method(bytes,__add__) {
234 METHOD_TAKES_EXACTLY(1);
238 pushStringBuilderStr(&sb, (
char*)self->bytes, self->length);
239 pushStringBuilderStr(&sb, (
char*)them->
bytes, them->
length);
241 return finishStringBuilderBytes(&sb);
244 FUNC_SIG(bytesiterator,__init__);
246 KRK_Method(bytes,__iter__) {
254 return OBJECT_VAL(output);
265 #define CURRENT_CTYPE struct BytesIterator *
266 #define IS_bytesiterator(o) krk_isInstanceOf(o,vm.baseClasses->bytesiteratorClass)
267 #define AS_bytesiterator(o) (struct BytesIterator*)AS_OBJECT(o)
269 static void _bytesiterator_gcscan(
KrkInstance *
self) {
273 KRK_Method(bytesiterator,__init__) {
274 METHOD_TAKES_EXACTLY(1);
281 KRK_Method(bytesiterator,__call__) {
283 size_t _counter =
self->i;
284 if (!IS_BYTES(_list) || _counter >= AS_BYTES(_list)->length) {
287 self->i = _counter + 1;
288 return INTEGER_VAL(AS_BYTES(_list)->bytes[_counter]);
293 #define CURRENT_CTYPE struct ByteArray *
295 static void _bytearray_gcscan(
KrkInstance *
self) {
299 KRK_Method(bytearray,__init__) {
300 METHOD_TAKES_AT_MOST(1);
303 }
else if (IS_BYTES(argv[1])) {
304 self->actual = OBJECT_VAL(
krk_newBytes(AS_BYTES(argv[1])->length, AS_BYTES(argv[1])->bytes));
305 }
else if (IS_INTEGER(argv[1])) {
306 self->actual = OBJECT_VAL(
krk_newBytes(AS_INTEGER(argv[1]),NULL));
307 memset(AS_BYTES(self->actual)->bytes, 0, AS_BYTES(self->actual)->length);
315 #define IS_bytearray(o) (krk_isInstanceOf(o,vm.baseClasses->bytearrayClass) && IS_BYTES(AS_bytearray(o)->actual))
318 KRK_Method(bytearray,__eq__) {
319 if (!IS_bytearray(argv[1]))
return BOOLEAN_VAL(0);
320 struct ByteArray * them = AS_bytearray(argv[1]);
324 KRK_Method(bytearray,__repr__) {
327 pushStringBuilderStr(&sb,
"bytearray(", 10);
328 if (!krk_pushStringBuilderFormat(&sb,
"%R", self->actual)) {
332 pushStringBuilder(&sb,
')');
333 return finishStringBuilder(&sb);
336 KRK_Method(bytearray,__getitem__) {
337 METHOD_TAKES_EXACTLY(1);
339 if (IS_INTEGER(argv[1])) {
340 CHECK_ARG(1,
int,krk_integer_type,asInt);
342 if (asInt < 0) asInt += (long)AS_BYTES(self->actual)->length;
343 if (asInt < 0 || asInt >= (
long)AS_BYTES(self->actual)->length) {
344 return krk_runtimeError(
vm.exceptions->indexError,
"bytearray index out of range: %d", (
int)asInt);
347 return INTEGER_VAL(AS_BYTES(self->actual)->bytes[asInt]);
348 }
else if (IS_slice(argv[1])) {
349 KRK_SLICER(argv[1],AS_BYTES(self->actual)->length) {
354 krk_integer_type len = end - start;
355 return OBJECT_VAL(
krk_newBytes(len, &AS_BYTES(self->actual)->bytes[start]));
358 krk_integer_type i = start;
359 while ((step < 0) ? (i > end) : (i < end)) {
360 pushStringBuilder(&sb, AS_BYTES(self->actual)->bytes[i]);
363 return finishStringBuilderBytes(&sb);
367 return TYPE_ERROR(
int or slice, argv[1]);
371 KRK_Method(bytearray,__setitem__) {
372 METHOD_TAKES_EXACTLY(2);
373 CHECK_ARG(1,
int,krk_integer_type,asInt);
374 CHECK_ARG(2,
int,krk_integer_type,val);
376 if (asInt < 0) asInt += (long)AS_BYTES(self->actual)->length;
377 if (asInt < 0 || asInt >= (
long)AS_BYTES(self->actual)->length) {
378 return krk_runtimeError(
vm.exceptions->indexError,
"bytearray index out of range: %d", (
int)asInt);
380 AS_BYTES(self->actual)->bytes[asInt] = val;
382 return INTEGER_VAL(AS_BYTES(self->actual)->bytes[asInt]);
385 KRK_Method(bytearray,__len__) {
386 return INTEGER_VAL(AS_BYTES(self->actual)->length);
389 KRK_Method(bytearray,__contains__) {
390 METHOD_TAKES_EXACTLY(1);
391 CHECK_ARG(1,
int,krk_integer_type,val);
392 for (
size_t i = 0; i < AS_BYTES(self->actual)->length; ++i) {
393 if (AS_BYTES(self->actual)->bytes[i] == val)
return BOOLEAN_VAL(1);
395 return BOOLEAN_VAL(0);
398 KRK_Method(bytearray,decode) {
400 return OBJECT_VAL(
krk_copyString((
char*)AS_BYTES(self->actual)->bytes, AS_BYTES(self->actual)->length));
403 KRK_Method(bytearray,__iter__) {
408 FUNC_NAME(bytesiterator,__init__)(2, (
KrkValue[]){
krk_peek(0),
self->actual},0);
411 return OBJECT_VAL(output);
416 void _createAndBind_bytesClass(
void) {
417 KrkClass * bytes = ADD_BASE_CLASS(
vm.baseClasses->bytesClass,
"bytes",
vm.baseClasses->objectClass);
418 bytes->
obj.
flags |= KRK_OBJ_FLAGS_NO_INHERIT;
420 KRK_DOC(BIND_STATICMETHOD(bytes,__new__),
421 "@brief An array of bytes.\n"
422 "@arguments iter=None\n\n"
423 "Creates a new @ref bytes object. If @p iter is provided, it should be a @ref tuple or @ref list "
424 "of integers within the range @c 0 and @c 255.");
425 BIND_METHOD(bytes,__repr__);
426 BIND_METHOD(bytes,__len__);
427 BIND_METHOD(bytes,__contains__);
428 BIND_METHOD(bytes,__getitem__);
429 BIND_METHOD(bytes,__eq__);
430 BIND_METHOD(bytes,__add__);
431 BIND_METHOD(bytes,__iter__);
432 BIND_METHOD(bytes,__hash__);
433 BIND_METHOD(bytes,decode);
434 BIND_METHOD(bytes,join);
437 KrkClass * bytesiterator = ADD_BASE_CLASS(
vm.baseClasses->bytesiteratorClass,
"bytesiterator",
vm.baseClasses->objectClass);
438 bytesiterator->
obj.
flags |= KRK_OBJ_FLAGS_NO_INHERIT;
440 bytesiterator->
_ongcscan = _bytesiterator_gcscan;
441 BIND_METHOD(bytesiterator,__init__);
442 BIND_METHOD(bytesiterator,__call__);
445 KrkClass * bytearray = ADD_BASE_CLASS(
vm.baseClasses->bytearrayClass,
"bytearray",
vm.baseClasses->objectClass);
447 bytearray->
_ongcscan = _bytearray_gcscan;
448 KRK_DOC(BIND_METHOD(bytearray,__init__),
449 "@brief A mutable array of bytes.\n"
450 "@arguments bytes=None");
451 BIND_METHOD(bytearray,__repr__);
452 BIND_METHOD(bytearray,__len__);
453 BIND_METHOD(bytearray,__contains__);
454 BIND_METHOD(bytearray,__getitem__);
455 BIND_METHOD(bytearray,__setitem__);
456 BIND_METHOD(bytearray,__eq__);
457 BIND_METHOD(bytearray,__iter__);
458 BIND_METHOD(bytearray,decode);
KrkValue krk_runtimeError(KrkClass *type, const char *fmt,...)
Produce and raise an exception with a formatted message.
Functions for dealing with garbage collection and memory allocation.
void krk_markValue(KrkValue value)
During a GC scan cycle, mark a value as used.
Immutable sequence of bytes.
size_t length
Length of data in bytes.
uint8_t * bytes
Pointer to separately-stored bytes data.
KrkBytes * krk_newBytes(size_t length, uint8_t *source)
Create a new byte array.
KrkCleanupCallback _ongcscan
C function to call when the garbage collector visits an instance of this class in the scan phase.
size_t allocSize
Size to allocate when creating instances of this class.
void krk_finalizeClass(KrkClass *_class)
Finalize a class by collecting pointers to core methods.
KrkInstance * krk_newInstance(KrkClass *_class)
Create a new instance of the given class.
uint32_t hash
Cached hash value for table keys.
uint16_t flags
General object flags, mostly related to garbage collection.
KrkString * krk_copyString(const char *chars, size_t length)
Obtain a string object representation of the given C string.
Stack reference or primative value.
int krk_valuesEqual(KrkValue a, KrkValue b)
Compare two values for equality.
Inline flexible string array.
Utilities for creating native bindings.
KrkValue krk_discardStringBuilder(struct StringBuilder *sb)
Discard the contents of a string builder.
int krk_unpackIterable(KrkValue iterable, void *context, int callback(void *, const KrkValue *, size_t))
Unpack an iterable.
#define KRK_DOC(thing, text)
Attach documentation to a thing of various types.
Definitions for primitive stack references.
Core API for the bytecode virtual machine.
#define vm
Convenience macro for namespacing.
KrkValue krk_pop(void)
Pop the top of the stack.
void krk_push(KrkValue value)
Push a stack value.
KrkValue krk_peek(int distance)
Peek down from the top of the stack.