Extended bytes, bytesiterator; added bytearray

This commit is contained in:
K. Lange 2021-10-13 20:52:39 +09:00
parent f1928b2526
commit b4887a78b0
3 changed files with 191 additions and 26 deletions

View File

@ -207,8 +207,8 @@ static inline KrkValue discardStringBuilder(struct StringBuilder * sb) {
#define IS_dictkeys(o) krk_isInstanceOf(o,vm.baseClasses->dictkeysClass)
#define AS_dictkeys(o) ((struct DictKeys*)AS_OBJECT(o))
#define IS_bytesiterator(o) (krk_isInstanceOf(o,vm.baseClasses->bytesiteratorClass))
#define AS_bytesiterator(o) (AS_INSTANCE(o))
#define IS_bytearray(o) (krk_isInstanceOf(o,vm.baseClasses->bytearrayClass))
#define AS_bytearray(o) ((struct ByteArray*)AS_INSTANCE(o))
#ifndef unpackError
#define unpackError(fromInput) return krk_runtimeError(vm.exceptions->typeError, "'%s' object is not iterable", krk_typeName(fromInput));

View File

@ -166,6 +166,7 @@ struct BaseClasses {
KrkClass * codeobjectClass; /**< Static compiled bytecode container (KrkCodeObject) */
KrkClass * generatorClass; /**< Generator object. */
KrkClass * notImplClass; /**< NotImplementedType */
KrkClass * bytearrayClass; /**< Mutable array of bytes */
};
/**

View File

@ -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__,{
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;
}
if (!krk_tableGet(&self->fields, OBJECT_VAL(S("i")), &_counter)) {
errorStr = "no index";
goto _corrupt;
}
if ((size_t)AS_INTEGER(_counter) >= AS_BYTES(_bytes)->length) {
KrkValue _list = self->l;
size_t _counter = self->i;
if (_counter >= AS_BYTES(_list)->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)]);
self->i = _counter + 1;
return INTEGER_VAL(AS_BYTES(_list)->bytes[_counter]);
}
_corrupt:
return krk_runtimeError(vm.exceptions->typeError, "Corrupt bytes iterator: %s", errorStr);
})
#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();
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);
}
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;
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);
}
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);
}