|
@@ -4,6 +4,11 @@
|
|
|
#include <kuroko/memory.h>
|
|
|
#include <kuroko/util.h>
|
|
|
|
|
|
+struct ByteArray {
|
|
|
+ KrkInstance inst;
|
|
|
+ KrkValue actual;
|
|
|
+};
|
|
|
+
|
|
|
#define AS_bytes(o) AS_BYTES(o)
|
|
|
#define CURRENT_CTYPE KrkBytes *
|
|
|
#define CURRENT_NAME self
|
|
@@ -39,6 +44,10 @@ KRK_METHOD(bytes,__init__,{
|
|
|
out->bytes[i] = AS_INTEGER(AS_LIST(argv[1])->values[i]);
|
|
|
}
|
|
|
return krk_pop();
|
|
|
+ } else if (IS_bytearray(argv[1])) {
|
|
|
+ return OBJECT_VAL(krk_newBytes(
|
|
|
+ AS_BYTES(AS_bytearray(argv[1])->actual)->length,
|
|
|
+ AS_BYTES(AS_bytearray(argv[1])->actual)->bytes));
|
|
|
}
|
|
|
|
|
|
return krk_runtimeError(vm.exceptions->typeError, "Can not convert '%s' to bytes", krk_typeName(argv[1]));
|
|
@@ -177,6 +186,25 @@ KRK_METHOD(bytes,__add__,{
|
|
|
return finishStringBuilderBytes(&sb);
|
|
|
})
|
|
|
|
|
|
+#define BYTES_WRAP_SOFT(val) \
|
|
|
+ if (val < 0) val += self->length; \
|
|
|
+ if (val < 0) val = 0; \
|
|
|
+ if (val > (krk_integer_type)self->length) val = self->length
|
|
|
+
|
|
|
+KRK_METHOD(bytes,__getslice__,{
|
|
|
+ METHOD_TAKES_EXACTLY(2);
|
|
|
+ if (!(IS_INTEGER(argv[1]) || IS_NONE(argv[1]))) return TYPE_ERROR(int or None, argv[1]);
|
|
|
+ if (!(IS_INTEGER(argv[2]) || IS_NONE(argv[2]))) return TYPE_ERROR(int or None, argv[2]);
|
|
|
+ krk_integer_type start = IS_NONE(argv[1]) ? 0 : AS_INTEGER(argv[1]);
|
|
|
+ krk_integer_type end = IS_NONE(argv[2]) ? (krk_integer_type)self->length : AS_INTEGER(argv[2]);
|
|
|
+ BYTES_WRAP_SOFT(start);
|
|
|
+ BYTES_WRAP_SOFT(end);
|
|
|
+ if (end < start) end = start;
|
|
|
+ krk_integer_type len = end - start;
|
|
|
+
|
|
|
+ return OBJECT_VAL(krk_newBytes(len, &self->bytes[start]));
|
|
|
+})
|
|
|
+
|
|
|
FUNC_SIG(bytesiterator,__init__);
|
|
|
|
|
|
KRK_METHOD(bytes,__iter__,{
|
|
@@ -191,40 +219,155 @@ KRK_METHOD(bytes,__iter__,{
|
|
|
})
|
|
|
|
|
|
#undef CURRENT_CTYPE
|
|
|
-#define CURRENT_CTYPE KrkInstance *
|
|
|
+
|
|
|
+struct BytesIterator {
|
|
|
+ KrkInstance inst;
|
|
|
+ KrkValue l;
|
|
|
+ size_t i;
|
|
|
+};
|
|
|
+
|
|
|
+#define CURRENT_CTYPE struct BytesIterator *
|
|
|
+#define IS_bytesiterator(o) krk_isInstanceOf(o,vm.baseClasses->bytesiteratorClass)
|
|
|
+#define AS_bytesiterator(o) (struct BytesIterator*)AS_OBJECT(o)
|
|
|
+
|
|
|
+static void _bytesiterator_gcscan(KrkInstance * self) {
|
|
|
+ krk_markValue(((struct BytesIterator*)self)->l);
|
|
|
+}
|
|
|
+
|
|
|
KRK_METHOD(bytesiterator,__init__,{
|
|
|
METHOD_TAKES_EXACTLY(1);
|
|
|
- CHECK_ARG(1,bytes,KrkBytes*,base);
|
|
|
- krk_push(OBJECT_VAL(self));
|
|
|
- krk_attachNamedObject(&self->fields, "s", (KrkObj*)base);
|
|
|
- krk_attachNamedValue(&self->fields, "i", INTEGER_VAL(0));
|
|
|
- return krk_pop();
|
|
|
+ CHECK_ARG(1,bytes,KrkBytes*,bytes);
|
|
|
+ self->l = argv[1];
|
|
|
+ self->i = 0;
|
|
|
+ return argv[0];
|
|
|
})
|
|
|
|
|
|
KRK_METHOD(bytesiterator,__call__,{
|
|
|
+ KrkValue _list = self->l;
|
|
|
+ size_t _counter = self->i;
|
|
|
+ if (_counter >= AS_BYTES(_list)->length) {
|
|
|
+ return argv[0];
|
|
|
+ } else {
|
|
|
+ self->i = _counter + 1;
|
|
|
+ return INTEGER_VAL(AS_BYTES(_list)->bytes[_counter]);
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+#undef CURRENT_CTYPE
|
|
|
+#define CURRENT_CTYPE struct ByteArray *
|
|
|
+
|
|
|
+static void _bytearray_gcscan(KrkInstance * self) {
|
|
|
+ krk_markValue(((struct ByteArray*)self)->actual);
|
|
|
+}
|
|
|
+
|
|
|
+KRK_METHOD(bytearray,__init__,{
|
|
|
+ METHOD_TAKES_AT_MOST(1);
|
|
|
+ if (argc < 2) {
|
|
|
+ self->actual = OBJECT_VAL(krk_newBytes(0,NULL));
|
|
|
+ } else if (IS_BYTES(argv[1])) {
|
|
|
+ self->actual = OBJECT_VAL(krk_newBytes(AS_BYTES(argv[1])->length, AS_BYTES(argv[1])->bytes));
|
|
|
+ } else if (IS_INTEGER(argv[1])) {
|
|
|
+ self->actual = OBJECT_VAL(krk_newBytes(AS_INTEGER(argv[1]),NULL));
|
|
|
+ } else {
|
|
|
+ return krk_runtimeError(vm.exceptions->valueError, "expected bytes");
|
|
|
+ }
|
|
|
+ return argv[0];
|
|
|
+})
|
|
|
+
|
|
|
+/* bytes objects are not interned; need to do this the old-fashioned way. */
|
|
|
+KRK_METHOD(bytearray,__eq__,{
|
|
|
+ if (!IS_bytearray(argv[1])) return BOOLEAN_VAL(0);
|
|
|
+ struct ByteArray * them = AS_bytearray(argv[1]);
|
|
|
+ return BOOLEAN_VAL(krk_valuesEqual(self->actual, them->actual));
|
|
|
+})
|
|
|
+
|
|
|
+KRK_METHOD(bytearray,__repr__,{
|
|
|
METHOD_TAKES_NONE();
|
|
|
- KrkValue _bytes;
|
|
|
- KrkValue _counter;
|
|
|
- const char * errorStr = NULL;
|
|
|
- if (!krk_tableGet(&self->fields, OBJECT_VAL(S("s")), &_bytes)) {
|
|
|
- errorStr = "no str pointer";
|
|
|
- goto _corrupt;
|
|
|
+ struct StringBuilder sb = {0};
|
|
|
+ pushStringBuilderStr(&sb, "bytearray(", 10);
|
|
|
+
|
|
|
+ krk_push(self->actual);
|
|
|
+ KrkValue repred_bytes = krk_callDirect(vm.baseClasses->bytesClass->_reprer, 1);
|
|
|
+ pushStringBuilderStr(&sb, AS_STRING(repred_bytes)->chars, AS_STRING(repred_bytes)->length);
|
|
|
+ pushStringBuilder(&sb,')');
|
|
|
+ return finishStringBuilder(&sb);
|
|
|
+})
|
|
|
+
|
|
|
+KRK_METHOD(bytearray,__getitem__,{
|
|
|
+ METHOD_TAKES_EXACTLY(1);
|
|
|
+ CHECK_ARG(1,int,krk_integer_type,asInt);
|
|
|
+
|
|
|
+ if (asInt < 0) asInt += (long)AS_BYTES(self->actual)->length;
|
|
|
+ if (asInt < 0 || asInt >= (long)AS_BYTES(self->actual)->length) {
|
|
|
+ return krk_runtimeError(vm.exceptions->indexError, "bytearray index out of range: %d", (int)asInt);
|
|
|
}
|
|
|
- if (!krk_tableGet(&self->fields, OBJECT_VAL(S("i")), &_counter)) {
|
|
|
- errorStr = "no index";
|
|
|
- goto _corrupt;
|
|
|
+
|
|
|
+ return INTEGER_VAL(AS_BYTES(self->actual)->bytes[asInt]);
|
|
|
+})
|
|
|
+
|
|
|
+KRK_METHOD(bytearray,__setitem__,{
|
|
|
+ METHOD_TAKES_EXACTLY(2);
|
|
|
+ CHECK_ARG(1,int,krk_integer_type,asInt);
|
|
|
+ CHECK_ARG(2,int,krk_integer_type,val);
|
|
|
+
|
|
|
+ if (asInt < 0) asInt += (long)AS_BYTES(self->actual)->length;
|
|
|
+ if (asInt < 0 || asInt >= (long)AS_BYTES(self->actual)->length) {
|
|
|
+ return krk_runtimeError(vm.exceptions->indexError, "bytearray index out of range: %d", (int)asInt);
|
|
|
}
|
|
|
+ AS_BYTES(self->actual)->bytes[asInt] = val;
|
|
|
|
|
|
- if ((size_t)AS_INTEGER(_counter) >= AS_BYTES(_bytes)->length) {
|
|
|
- return argv[0];
|
|
|
- } else {
|
|
|
- krk_attachNamedValue(&self->fields, "i", INTEGER_VAL(AS_INTEGER(_counter)+1));
|
|
|
- return INTEGER_VAL(AS_BYTES(_bytes)->bytes[AS_INTEGER(_counter)]);
|
|
|
+ return INTEGER_VAL(AS_BYTES(self->actual)->bytes[asInt]);
|
|
|
+})
|
|
|
+
|
|
|
+KRK_METHOD(bytearray,__len__,{
|
|
|
+ return INTEGER_VAL(AS_BYTES(self->actual)->length);
|
|
|
+})
|
|
|
+
|
|
|
+KRK_METHOD(bytearray,__contains__,{
|
|
|
+ METHOD_TAKES_EXACTLY(1);
|
|
|
+ CHECK_ARG(1,int,krk_integer_type,val);
|
|
|
+ for (size_t i = 0; i < AS_BYTES(self->actual)->length; ++i) {
|
|
|
+ if (AS_BYTES(self->actual)->bytes[i] == val) return BOOLEAN_VAL(1);
|
|
|
}
|
|
|
-_corrupt:
|
|
|
- return krk_runtimeError(vm.exceptions->typeError, "Corrupt bytes iterator: %s", errorStr);
|
|
|
+ return BOOLEAN_VAL(0);
|
|
|
})
|
|
|
|
|
|
+KRK_METHOD(bytearray,decode,{
|
|
|
+ METHOD_TAKES_NONE();
|
|
|
+ return OBJECT_VAL(krk_copyString((char*)AS_BYTES(self->actual)->bytes, AS_BYTES(self->actual)->length));
|
|
|
+})
|
|
|
+
|
|
|
+#define BYTEARRAY_WRAP_SOFT(val) \
|
|
|
+ if (val < 0) val += AS_BYTES(self->actual)->length; \
|
|
|
+ if (val < 0) val = 0; \
|
|
|
+ if (val > (krk_integer_type)AS_BYTES(self->actual)->length) val = AS_BYTES(self->actual)->length
|
|
|
+
|
|
|
+KRK_METHOD(bytearray,__getslice__,{
|
|
|
+ METHOD_TAKES_EXACTLY(2);
|
|
|
+ if (!(IS_INTEGER(argv[1]) || IS_NONE(argv[1]))) return TYPE_ERROR(int or None, argv[1]);
|
|
|
+ if (!(IS_INTEGER(argv[2]) || IS_NONE(argv[2]))) return TYPE_ERROR(int or None, argv[2]);
|
|
|
+ krk_integer_type start = IS_NONE(argv[1]) ? 0 : AS_INTEGER(argv[1]);
|
|
|
+ krk_integer_type end = IS_NONE(argv[2]) ? (krk_integer_type)AS_BYTES(self->actual)->length : AS_INTEGER(argv[2]);
|
|
|
+ BYTEARRAY_WRAP_SOFT(start);
|
|
|
+ BYTEARRAY_WRAP_SOFT(end);
|
|
|
+ if (end < start) end = start;
|
|
|
+ krk_integer_type len = end - start;
|
|
|
+
|
|
|
+ return OBJECT_VAL(krk_newBytes(len, &AS_BYTES(self->actual)->bytes[start]));
|
|
|
+})
|
|
|
+
|
|
|
+KRK_METHOD(bytearray,__iter__,{
|
|
|
+ METHOD_TAKES_NONE();
|
|
|
+ KrkInstance * output = krk_newInstance(vm.baseClasses->bytesiteratorClass);
|
|
|
+
|
|
|
+ krk_push(OBJECT_VAL(output));
|
|
|
+ FUNC_NAME(bytesiterator,__init__)(2, (KrkValue[]){krk_peek(0), self->actual},0);
|
|
|
+ krk_pop();
|
|
|
+
|
|
|
+ return OBJECT_VAL(output);
|
|
|
+})
|
|
|
+
|
|
|
+
|
|
|
_noexport
|
|
|
void _createAndBind_bytesClass(void) {
|
|
|
KrkClass * bytes = ADD_BASE_CLASS(vm.baseClasses->bytesClass, "bytes", vm.baseClasses->objectClass);
|
|
@@ -237,6 +380,7 @@ void _createAndBind_bytesClass(void) {
|
|
|
BIND_METHOD(bytes,__len__);
|
|
|
BIND_METHOD(bytes,__contains__);
|
|
|
BIND_METHOD(bytes,__getitem__);
|
|
|
+ BIND_METHOD(bytes,__getslice__);
|
|
|
BIND_METHOD(bytes,__eq__);
|
|
|
BIND_METHOD(bytes,__add__);
|
|
|
BIND_METHOD(bytes,__iter__);
|
|
@@ -247,7 +391,27 @@ void _createAndBind_bytesClass(void) {
|
|
|
krk_finalizeClass(bytes);
|
|
|
|
|
|
KrkClass * bytesiterator = ADD_BASE_CLASS(vm.baseClasses->bytesiteratorClass, "bytesiterator", vm.baseClasses->objectClass);
|
|
|
+ bytesiterator->allocSize = sizeof(struct BytesIterator);
|
|
|
+ bytesiterator->_ongcscan = _bytesiterator_gcscan;
|
|
|
BIND_METHOD(bytesiterator,__init__);
|
|
|
BIND_METHOD(bytesiterator,__call__);
|
|
|
krk_finalizeClass(bytesiterator);
|
|
|
+
|
|
|
+ KrkClass * bytearray = ADD_BASE_CLASS(vm.baseClasses->bytearrayClass, "bytearray", vm.baseClasses->objectClass);
|
|
|
+ bytearray->allocSize = sizeof(struct ByteArray);
|
|
|
+ bytearray->_ongcscan = _bytearray_gcscan;
|
|
|
+ KRK_DOC(BIND_METHOD(bytearray,__init__),
|
|
|
+ "@brief A mutable array of bytes.\n"
|
|
|
+ "@arguments bytes=None");
|
|
|
+ BIND_METHOD(bytearray,__repr__);
|
|
|
+ BIND_METHOD(bytearray,__len__);
|
|
|
+ BIND_METHOD(bytearray,__contains__);
|
|
|
+ BIND_METHOD(bytearray,__getitem__);
|
|
|
+ BIND_METHOD(bytearray,__setitem__);
|
|
|
+ BIND_METHOD(bytearray,__getslice__);
|
|
|
+ BIND_METHOD(bytearray,__eq__);
|
|
|
+ BIND_METHOD(bytearray,__iter__);
|
|
|
+ BIND_METHOD(bytearray,decode);
|
|
|
+ krk_defineNative(&bytearray->methods,"__str__",FUNC_NAME(bytearray,__repr__)); /* alias */
|
|
|
+ krk_finalizeClass(bytearray);
|
|
|
}
|