useful methods for bytes
This commit is contained in:
parent
e0adfcdc80
commit
22453f42e6
171
src/obj_bytes.c
171
src/obj_bytes.c
@ -4,11 +4,18 @@
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
|
||||
static KrkValue _bytes_init(int argc, KrkValue argv[], int hasKw) {
|
||||
if (argc == 1) {
|
||||
#define AS_bytes(o) AS_BYTES(o)
|
||||
#define CURRENT_CTYPE KrkBytes *
|
||||
#define CURRENT_NAME self
|
||||
|
||||
#define IS_bytes(o) (IS_BYTES(o) || krk_isInstanceOf(o, vm.baseClasses->bytesClass))
|
||||
KRK_METHOD(bytes,__init__,{
|
||||
if (argc < 2) {
|
||||
return OBJECT_VAL(krk_newBytes(0,NULL));
|
||||
}
|
||||
METHOD_TAKES_AT_MOST(1);
|
||||
|
||||
/* TODO: Use generic unpacker */
|
||||
if (IS_TUPLE(argv[1])) {
|
||||
KrkBytes * out = krk_newBytes(AS_TUPLE(argv[1])->values.count, NULL);
|
||||
krk_push(OBJECT_VAL(out));
|
||||
@ -20,13 +27,27 @@ static KrkValue _bytes_init(int argc, KrkValue argv[], int hasKw) {
|
||||
}
|
||||
krk_bytesUpdateHash(out);
|
||||
return krk_pop();
|
||||
} else if (IS_list(argv[1])) {
|
||||
KrkBytes * out = krk_newBytes(AS_LIST(argv[1])->count, NULL);
|
||||
krk_push(OBJECT_VAL(out));
|
||||
for (size_t i = 0; i < AS_LIST(argv[1])->count; ++i) {
|
||||
if (!IS_INTEGER(AS_LIST(argv[1])->values[i])) {
|
||||
return krk_runtimeError(vm.exceptions->typeError, "bytes(): expected list of ints, not of '%s'", krk_typeName(AS_LIST(argv[1])->values[i]));
|
||||
}
|
||||
out->bytes[i] = AS_INTEGER(AS_LIST(argv[1])->values[i]);
|
||||
}
|
||||
krk_bytesUpdateHash(out);
|
||||
return krk_pop();
|
||||
}
|
||||
|
||||
return krk_runtimeError(vm.exceptions->typeError, "Can not convert '%s' to bytes", krk_typeName(argv[1]));
|
||||
}
|
||||
})
|
||||
|
||||
#undef IS_bytes
|
||||
#define IS_bytes(o) IS_BYTES(o)
|
||||
|
||||
/* bytes objects are not interned; need to do this the old-fashioned way. */
|
||||
static KrkValue _bytes_eq(int argc, KrkValue argv[], int hasKw) {
|
||||
KRK_METHOD(bytes,__eq__,{
|
||||
if (!IS_BYTES(argv[1])) return BOOLEAN_VAL(0);
|
||||
KrkBytes * self = AS_BYTES(argv[0]);
|
||||
KrkBytes * them = AS_BYTES(argv[1]);
|
||||
@ -36,61 +57,52 @@ static KrkValue _bytes_eq(int argc, KrkValue argv[], int hasKw) {
|
||||
if (self->bytes[i] != them->bytes[i]) return BOOLEAN_VAL(0);
|
||||
}
|
||||
return BOOLEAN_VAL(1);
|
||||
}
|
||||
})
|
||||
|
||||
#define PUSH_CHAR(c) do { if (stringCapacity < stringLength + 1) { \
|
||||
size_t old = stringCapacity; stringCapacity = GROW_CAPACITY(old); \
|
||||
stringBytes = GROW_ARRAY(char, stringBytes, old, stringCapacity); \
|
||||
} stringBytes[stringLength++] = c; } while (0)
|
||||
#define AT_END() (self->length == 0 || i == self->length - 1)
|
||||
|
||||
static KrkValue _bytes_repr(int argc, KrkValue argv[], int hasKw) {
|
||||
size_t stringCapacity = 0;
|
||||
size_t stringLength = 0;
|
||||
char * stringBytes = NULL;
|
||||
KRK_METHOD(bytes,__repr__,{
|
||||
struct StringBuilder sb = {0};
|
||||
|
||||
PUSH_CHAR('b');
|
||||
PUSH_CHAR('\'');
|
||||
pushStringBuilder(&sb, 'b');
|
||||
pushStringBuilder(&sb, '\'');
|
||||
|
||||
for (size_t i = 0; i < AS_BYTES(argv[0])->length; ++i) {
|
||||
uint8_t ch = AS_BYTES(argv[0])->bytes[i];
|
||||
switch (ch) {
|
||||
case '\\': PUSH_CHAR('\\'); PUSH_CHAR('\\'); break;
|
||||
case '\'': PUSH_CHAR('\\'); PUSH_CHAR('\''); break;
|
||||
case '\a': PUSH_CHAR('\\'); PUSH_CHAR('a'); break;
|
||||
case '\b': PUSH_CHAR('\\'); PUSH_CHAR('b'); break;
|
||||
case '\f': PUSH_CHAR('\\'); PUSH_CHAR('f'); break;
|
||||
case '\n': PUSH_CHAR('\\'); PUSH_CHAR('n'); break;
|
||||
case '\r': PUSH_CHAR('\\'); PUSH_CHAR('r'); break;
|
||||
case '\t': PUSH_CHAR('\\'); PUSH_CHAR('t'); break;
|
||||
case '\v': PUSH_CHAR('\\'); PUSH_CHAR('v'); break;
|
||||
case '\\': pushStringBuilder(&sb, '\\'); pushStringBuilder(&sb, '\\'); break;
|
||||
case '\'': pushStringBuilder(&sb, '\\'); pushStringBuilder(&sb, '\''); break;
|
||||
case '\a': pushStringBuilder(&sb, '\\'); pushStringBuilder(&sb, 'a'); break;
|
||||
case '\b': pushStringBuilder(&sb, '\\'); pushStringBuilder(&sb, 'b'); break;
|
||||
case '\f': pushStringBuilder(&sb, '\\'); pushStringBuilder(&sb, 'f'); break;
|
||||
case '\n': pushStringBuilder(&sb, '\\'); pushStringBuilder(&sb, 'n'); break;
|
||||
case '\r': pushStringBuilder(&sb, '\\'); pushStringBuilder(&sb, 'r'); break;
|
||||
case '\t': pushStringBuilder(&sb, '\\'); pushStringBuilder(&sb, 't'); break;
|
||||
case '\v': pushStringBuilder(&sb, '\\'); pushStringBuilder(&sb, 'v'); break;
|
||||
default: {
|
||||
if (ch < ' ' || ch >= 0x7F) {
|
||||
PUSH_CHAR('\\');
|
||||
PUSH_CHAR('x');
|
||||
pushStringBuilder(&sb, '\\');
|
||||
pushStringBuilder(&sb, 'x');
|
||||
char hex[3];
|
||||
sprintf(hex,"%02x", ch);
|
||||
PUSH_CHAR(hex[0]);
|
||||
PUSH_CHAR(hex[1]);
|
||||
pushStringBuilder(&sb, hex[0]);
|
||||
pushStringBuilder(&sb, hex[1]);
|
||||
} else {
|
||||
PUSH_CHAR(ch);
|
||||
pushStringBuilder(&sb, ch);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PUSH_CHAR('\'');
|
||||
pushStringBuilder(&sb, '\'');
|
||||
|
||||
KrkValue tmp = OBJECT_VAL(krk_copyString(stringBytes, stringLength));
|
||||
if (stringBytes) FREE_ARRAY(char,stringBytes,stringCapacity);
|
||||
return tmp;
|
||||
}
|
||||
return finishStringBuilder(&sb);
|
||||
})
|
||||
|
||||
static KrkValue _bytes_get(int argc, KrkValue argv[], int hasKw) {
|
||||
if (argc < 2) return krk_runtimeError(vm.exceptions->argumentError, "bytes.__get__(): expected one argument");
|
||||
KrkBytes * self = AS_BYTES(argv[0]);
|
||||
long asInt = AS_INTEGER(argv[1]);
|
||||
KRK_METHOD(bytes,__get__,{
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
CHECK_ARG(1,int,krk_integer_type,asInt);
|
||||
|
||||
if (asInt < 0) asInt += (long)self->length;
|
||||
if (asInt < 0 || asInt >= (long)self->length) {
|
||||
@ -98,34 +110,77 @@ static KrkValue _bytes_get(int argc, KrkValue argv[], int hasKw) {
|
||||
}
|
||||
|
||||
return INTEGER_VAL(self->bytes[asInt]);
|
||||
}
|
||||
})
|
||||
|
||||
static KrkValue _bytes_len(int argc, KrkValue argv[], int hasKw) {
|
||||
KRK_METHOD(bytes,__len__,{
|
||||
return INTEGER_VAL(AS_BYTES(argv[0])->length);
|
||||
}
|
||||
})
|
||||
|
||||
static KrkValue _bytes_contains(int argc, KrkValue argv[], int hasKw) {
|
||||
if (argc < 2) krk_runtimeError(vm.exceptions->argumentError, "bytes.__contains__(): expected one argument");
|
||||
KRK_METHOD(bytes,__contains__,{
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
return krk_runtimeError(vm.exceptions->notImplementedError, "not implemented");
|
||||
}
|
||||
})
|
||||
|
||||
static KrkValue _bytes_decode(int argc, KrkValue argv[], int hasKw) {
|
||||
/* TODO: Actually bother checking if this explodes, or support other encodings... */
|
||||
KRK_METHOD(bytes,decode,{
|
||||
METHOD_TAKES_NONE();
|
||||
return OBJECT_VAL(krk_copyString((char*)AS_BYTES(argv[0])->bytes, AS_BYTES(argv[0])->length));
|
||||
}
|
||||
})
|
||||
|
||||
#undef PUSH_CHAR
|
||||
KRK_METHOD(bytes,join,{
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
CHECK_ARG(1,list,KrkList*,iterable);
|
||||
|
||||
const char * errorStr = NULL;
|
||||
struct StringBuilder sb = {0};
|
||||
|
||||
for (size_t i = 0; i < iterable->values.count; ++i) {
|
||||
KrkValue value = iterable->values.values[i];
|
||||
if (!IS_BYTES(iterable->values.values[i])) {
|
||||
errorStr = krk_typeName(value);
|
||||
goto _expectedBytes;
|
||||
}
|
||||
krk_push(value);
|
||||
if (i > 0) {
|
||||
for (size_t j = 0; j < self->length; ++j) {
|
||||
pushStringBuilder(&sb, self->bytes[j]);
|
||||
}
|
||||
}
|
||||
for (size_t j = 0; j < AS_STRING(value)->length; ++j) {
|
||||
pushStringBuilder(&sb, AS_BYTES(value)->bytes[j]);
|
||||
}
|
||||
krk_pop();
|
||||
}
|
||||
|
||||
return finishStringBuilderBytes(&sb);
|
||||
|
||||
_expectedBytes:
|
||||
krk_runtimeError(vm.exceptions->typeError, "Expected bytes, got %s.", errorStr);
|
||||
discardStringBuilder(&sb);
|
||||
})
|
||||
|
||||
KRK_METHOD(bytes,__add__,{
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
CHECK_ARG(1,bytes,KrkBytes*,them);
|
||||
|
||||
struct StringBuilder sb = {0};
|
||||
pushStringBuilderStr(&sb, (char*)self->bytes, self->length);
|
||||
pushStringBuilderStr(&sb, (char*)them->bytes, them->length);
|
||||
|
||||
return finishStringBuilderBytes(&sb);
|
||||
})
|
||||
|
||||
_noexport
|
||||
void _createAndBind_bytesClass(void) {
|
||||
ADD_BASE_CLASS(vm.baseClasses->bytesClass, "bytes", vm.baseClasses->objectClass);
|
||||
krk_defineNative(&vm.baseClasses->bytesClass->methods, ".__init__", _bytes_init);
|
||||
krk_defineNative(&vm.baseClasses->bytesClass->methods, ".__str__", _bytes_repr);
|
||||
krk_defineNative(&vm.baseClasses->bytesClass->methods, ".__repr__", _bytes_repr);
|
||||
krk_defineNative(&vm.baseClasses->bytesClass->methods, ".decode", _bytes_decode);
|
||||
krk_defineNative(&vm.baseClasses->bytesClass->methods, ".__len__", _bytes_len);
|
||||
krk_defineNative(&vm.baseClasses->bytesClass->methods, ".__contains__", _bytes_contains);
|
||||
krk_defineNative(&vm.baseClasses->bytesClass->methods, ".__get__", _bytes_get);
|
||||
krk_defineNative(&vm.baseClasses->bytesClass->methods, ".__eq__", _bytes_eq);
|
||||
krk_finalizeClass(vm.baseClasses->bytesClass);
|
||||
KrkClass * bytes = ADD_BASE_CLASS(vm.baseClasses->bytesClass, "bytes", vm.baseClasses->objectClass);
|
||||
BIND_METHOD(bytes,__init__);
|
||||
BIND_METHOD(bytes,__repr__);
|
||||
BIND_METHOD(bytes,__len__);
|
||||
BIND_METHOD(bytes,__contains__);
|
||||
BIND_METHOD(bytes,__get__);
|
||||
BIND_METHOD(bytes,__eq__);
|
||||
BIND_METHOD(bytes,__add__);
|
||||
BIND_METHOD(bytes,decode);
|
||||
BIND_METHOD(bytes,join);
|
||||
krk_defineNative(&bytes->methods,".__str__",FUNC_NAME(bytes,__repr__)); /* alias */
|
||||
krk_finalizeClass(bytes);
|
||||
}
|
||||
|
@ -127,6 +127,12 @@ static inline KrkValue finishStringBuilder(struct StringBuilder * sb) {
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline KrkValue finishStringBuilderBytes(struct StringBuilder * sb) {
|
||||
KrkValue out = OBJECT_VAL(krk_newBytes(sb->length, (uint8_t*)sb->bytes));
|
||||
FREE_ARRAY(char,sb->bytes, sb->capacity);
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline KrkValue discardStringBuilder(struct StringBuilder * sb) {
|
||||
FREE_ARRAY(char,sb->bytes, sb->capacity);
|
||||
return NONE_VAL();
|
||||
|
Loading…
Reference in New Issue
Block a user