Implement slice objects, slice stepping
This is an initial implementation of slice stepping and slice objects. The __getslice__, __setslice__, and __delslice__ methods have been removed. Slice expressions are now turned into slice objects with the OP_SLICE instruction. Slice objects have a start, end, and step, all of which default to None. Slice objects are passed to __getitem__, et al., as a normal parameter. Support for slices in list.__getitem__, str.__getitem__, and bytes.__getitem__ has been implemented.
This commit is contained in:
parent
c750f76a57
commit
6613db6cd4
121
src/compiler.c
121
src/compiler.c
@ -861,75 +861,78 @@ static void expression(void) {
|
||||
parsePrecedence(PREC_CAN_ASSIGN);
|
||||
}
|
||||
|
||||
static void getitem(int exprType) {
|
||||
static void sliceExpression(void) {
|
||||
int isSlice = 0;
|
||||
if (match(TOKEN_COLON)) {
|
||||
emitByte(OP_NONE);
|
||||
isSlice = 1;
|
||||
} else {
|
||||
parsePrecedence(PREC_COMMA);
|
||||
parsePrecedence(PREC_CAN_ASSIGN);
|
||||
}
|
||||
if (isSlice || match(TOKEN_COLON)) {
|
||||
if (isSlice && match(TOKEN_COLON)) {
|
||||
error("Step value not supported in slice. (GH-11)");
|
||||
/* We have the start value, which is either something or None */
|
||||
if (check(TOKEN_RIGHT_SQUARE) || check(TOKEN_COMMA)) {
|
||||
/* foo[x:] */
|
||||
emitByte(OP_NONE);
|
||||
EMIT_OPERAND_OP(OP_SLICE, 2);
|
||||
} else {
|
||||
if (check(TOKEN_COLON)) {
|
||||
/* foo[x::... */
|
||||
emitByte(OP_NONE);
|
||||
} else {
|
||||
/* foo[x:e... */
|
||||
parsePrecedence(PREC_CAN_ASSIGN);
|
||||
}
|
||||
if (match(TOKEN_COLON) && !check(TOKEN_RIGHT_SQUARE) && !check(TOKEN_COMMA)) {
|
||||
/* foo[x:e:s] */
|
||||
parsePrecedence(PREC_CAN_ASSIGN);
|
||||
EMIT_OPERAND_OP(OP_SLICE, 3);
|
||||
} else {
|
||||
/* foo[x:e] */
|
||||
EMIT_OPERAND_OP(OP_SLICE, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void getitem(int exprType) {
|
||||
|
||||
sliceExpression();
|
||||
|
||||
if (match(TOKEN_COMMA)) {
|
||||
size_t argCount = 1;
|
||||
if (!check(TOKEN_RIGHT_SQUARE)) {
|
||||
do {
|
||||
sliceExpression();
|
||||
argCount++;
|
||||
} while (match(TOKEN_COMMA) && !check(TOKEN_RIGHT_SQUARE));
|
||||
}
|
||||
EMIT_OPERAND_OP(OP_TUPLE, argCount);
|
||||
}
|
||||
|
||||
consume(TOKEN_RIGHT_SQUARE, "Expected ']' after index.");
|
||||
if (exprType == EXPR_ASSIGN_TARGET) {
|
||||
if (matchComplexEnd()) {
|
||||
EMIT_OPERAND_OP(OP_DUP, 2);
|
||||
emitByte(OP_INVOKE_SETTER);
|
||||
emitByte(OP_POP);
|
||||
return;
|
||||
}
|
||||
if (match(TOKEN_RIGHT_SQUARE)) {
|
||||
emitByte(OP_NONE);
|
||||
} else {
|
||||
parsePrecedence(PREC_COMMA);
|
||||
consume(TOKEN_RIGHT_SQUARE, "Expected ']' after slice.");
|
||||
}
|
||||
if (exprType == EXPR_ASSIGN_TARGET) {
|
||||
if (matchComplexEnd()) {
|
||||
EMIT_OPERAND_OP(OP_DUP, 3);
|
||||
emitByte(OP_INVOKE_SETSLICE);
|
||||
emitByte(OP_POP);
|
||||
return;
|
||||
}
|
||||
exprType = EXPR_NORMAL;
|
||||
}
|
||||
if (exprType == EXPR_CAN_ASSIGN && (match(TOKEN_EQUAL))) {
|
||||
parsePrecedence(PREC_ASSIGNMENT);
|
||||
emitByte(OP_INVOKE_SETSLICE);
|
||||
} else if (exprType ==EXPR_CAN_ASSIGN && matchAssignment()) {
|
||||
/* o s e */
|
||||
emitBytes(OP_DUP, 2); /* o s e o */
|
||||
emitBytes(OP_DUP, 2); /* o s e o s */
|
||||
emitBytes(OP_DUP, 2); /* o s e o s e */
|
||||
emitByte(OP_INVOKE_GETSLICE); /* o s e v */
|
||||
assignmentValue();
|
||||
emitByte(OP_INVOKE_SETSLICE);
|
||||
} else if (exprType == EXPR_DEL_TARGET && checkEndOfDel()) {
|
||||
emitByte(OP_INVOKE_DELSLICE);
|
||||
} else {
|
||||
emitByte(OP_INVOKE_GETSLICE);
|
||||
}
|
||||
exprType = EXPR_NORMAL;
|
||||
}
|
||||
if (exprType == EXPR_CAN_ASSIGN && match(TOKEN_EQUAL)) {
|
||||
parsePrecedence(PREC_ASSIGNMENT);
|
||||
emitByte(OP_INVOKE_SETTER);
|
||||
} else if (exprType == EXPR_CAN_ASSIGN && matchAssignment()) {
|
||||
emitBytes(OP_DUP, 1); /* o e o */
|
||||
emitBytes(OP_DUP, 1); /* o e o e */
|
||||
emitByte(OP_INVOKE_GETTER); /* o e v */
|
||||
assignmentValue(); /* o e v a */
|
||||
emitByte(OP_INVOKE_SETTER); /* r */
|
||||
} else if (exprType == EXPR_DEL_TARGET && checkEndOfDel()) {
|
||||
emitByte(OP_INVOKE_DELETE);
|
||||
} else {
|
||||
consume(TOKEN_RIGHT_SQUARE, "Expected ']' after index.");
|
||||
if (exprType == EXPR_ASSIGN_TARGET) {
|
||||
if (matchComplexEnd()) {
|
||||
EMIT_OPERAND_OP(OP_DUP, 2);
|
||||
emitByte(OP_INVOKE_SETTER);
|
||||
emitByte(OP_POP);
|
||||
return;
|
||||
}
|
||||
exprType = EXPR_NORMAL;
|
||||
}
|
||||
if (exprType == EXPR_CAN_ASSIGN && match(TOKEN_EQUAL)) {
|
||||
parsePrecedence(PREC_ASSIGNMENT);
|
||||
emitByte(OP_INVOKE_SETTER);
|
||||
} else if (exprType == EXPR_CAN_ASSIGN && matchAssignment()) {
|
||||
emitBytes(OP_DUP, 1); /* o e o */
|
||||
emitBytes(OP_DUP, 1); /* o e o e */
|
||||
emitByte(OP_INVOKE_GETTER); /* o e v */
|
||||
assignmentValue(); /* o e v a */
|
||||
emitByte(OP_INVOKE_SETTER); /* r */
|
||||
} else if (exprType == EXPR_DEL_TARGET && checkEndOfDel()) {
|
||||
emitByte(OP_INVOKE_DELETE);
|
||||
} else {
|
||||
emitByte(OP_INVOKE_GETTER);
|
||||
}
|
||||
emitByte(OP_INVOKE_GETTER);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,10 +40,7 @@ typedef enum {
|
||||
OP_GREATER,
|
||||
OP_INHERIT,
|
||||
OP_INVOKE_DELETE,
|
||||
OP_INVOKE_DELSLICE,
|
||||
OP_INVOKE_GETSLICE,
|
||||
OP_INVOKE_GETTER,
|
||||
OP_INVOKE_SETSLICE,
|
||||
OP_INVOKE_SETTER,
|
||||
OP_IS,
|
||||
OP_LESS,
|
||||
@ -106,6 +103,7 @@ typedef enum {
|
||||
OP_MAKE_DICT,
|
||||
OP_MAKE_SET,
|
||||
OP_REVERSE,
|
||||
OP_SLICE,
|
||||
|
||||
/* Two opcode instructions */
|
||||
OP_JUMP_IF_FALSE_OR_POP,
|
||||
@ -149,6 +147,7 @@ typedef enum {
|
||||
OP_MAKE_DICT_LONG,
|
||||
OP_MAKE_SET_LONG,
|
||||
OP_REVERSE_LONG,
|
||||
OP_SLICE_LONG,
|
||||
} KrkOpCode;
|
||||
|
||||
/**
|
||||
|
@ -190,7 +190,6 @@ typedef struct KrkClass {
|
||||
|
||||
KrkObj * _getter; /**< @brief @c %__getitem__ Called when an instance is subscripted */
|
||||
KrkObj * _setter; /**< @brief @c %__setitem__ Called when a subscripted instance is assigned to */
|
||||
KrkObj * _getslice; /**< @brief @c %__getslice__ Called when a slice is used with a subscript access */
|
||||
KrkObj * _reprer; /**< @brief @c %__repr__ Called to create a reproducible string representation of an instance */
|
||||
KrkObj * _tostr; /**< @brief @c %__str__ Called to produce a string from an instance */
|
||||
KrkObj * _call; /**< @brief @c %__call__ Called when an instance is called like a function */
|
||||
@ -203,8 +202,6 @@ typedef struct KrkClass {
|
||||
KrkObj * _iter; /**< @brief @c %__iter__ Called by `for ... in ...`, etc. */
|
||||
KrkObj * _getattr; /**< @brief @c %__getattr__ Overrides normal behavior for attribute access */
|
||||
KrkObj * _dir; /**< @brief @c %__dir__ Overrides normal behavior for @c dir() */
|
||||
KrkObj * _setslice; /**< @brief @c %__setslice__ Called when a slice subscript is an assignment target */
|
||||
KrkObj * _delslice; /**< @brief @c %__delslice__ Called when a slice subscript is a `del` target */
|
||||
KrkObj * _contains; /**< @brief @c %__contains__ Called to resolve `in` (as a binary operator) */
|
||||
KrkObj * _descget; /**< @brief @c %__get__ Called when a descriptor object is bound as a property */
|
||||
KrkObj * _descset; /**< @brief @c %__set__ Called when a descriptor object is assigned to as a property */
|
||||
@ -336,6 +333,16 @@ struct KrkModule {
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* @extends KrkInstance
|
||||
*/
|
||||
struct KrkSlice {
|
||||
KrkInstance inst;
|
||||
KrkValue start;
|
||||
KrkValue end;
|
||||
KrkValue step;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Yield ownership of a C string to the GC and obtain a string object.
|
||||
* @memberof KrkString
|
||||
|
@ -213,6 +213,9 @@ static inline KrkValue discardStringBuilder(struct StringBuilder * sb) {
|
||||
#define IS_bytearray(o) (krk_isInstanceOf(o,vm.baseClasses->bytearrayClass))
|
||||
#define AS_bytearray(o) ((struct ByteArray*)AS_INSTANCE(o))
|
||||
|
||||
#define IS_slice(o) krk_isInstanceOf(o,vm.baseClasses->sliceClass)
|
||||
#define AS_slice(o) ((struct KrkSlice*)AS_INSTANCE(o))
|
||||
|
||||
#ifndef unpackError
|
||||
#define unpackError(fromInput) return krk_runtimeError(vm.exceptions->typeError, "'%s' object is not iterable", krk_typeName(fromInput));
|
||||
#endif
|
||||
@ -304,3 +307,10 @@ static inline void _setDoc_native(KrkNative * thing, const char * text, size_t s
|
||||
|
||||
#define BUILTIN_FUNCTION(name, func, docStr) KRK_DOC(krk_defineNative(&vm.builtins->fields, name, func), docStr)
|
||||
|
||||
extern 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);
|
||||
#define KRK_SLICER(arg,count) \
|
||||
krk_integer_type start; \
|
||||
krk_integer_type end; \
|
||||
krk_integer_type step; \
|
||||
if (krk_extractSlicer(_method_name, arg, count, &start, &end, &step))
|
||||
|
||||
|
@ -168,6 +168,7 @@ struct BaseClasses {
|
||||
KrkClass * notImplClass; /**< NotImplementedType */
|
||||
KrkClass * bytearrayClass; /**< Mutable array of bytes */
|
||||
KrkClass * dictvaluesClass; /**< Iterator over values of a dict */
|
||||
KrkClass * sliceClass; /**< Slice object */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -619,6 +620,12 @@ extern KrkValue krk_tuple_of(int argc, KrkValue argv[], int hasKw);
|
||||
*/
|
||||
extern KrkValue krk_set_of(int argc, KrkValue argv[], int hasKw);
|
||||
|
||||
/**
|
||||
* @brief Create a slice object.
|
||||
* @memberof KrkSlice
|
||||
*/
|
||||
extern KrkValue krk_slice_of(int argc, KrkValue argv[], int hasKw);
|
||||
|
||||
/**
|
||||
* @brief Call a callable on the stack with @p argCount arguments.
|
||||
*
|
||||
|
110
src/obj_bytes.c
110
src/obj_bytes.c
@ -123,14 +123,37 @@ KRK_METHOD(bytes,__repr__,{
|
||||
|
||||
KRK_METHOD(bytes,__getitem__,{
|
||||
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) {
|
||||
return krk_runtimeError(vm.exceptions->indexError, "bytes index out of range: %d", (int)asInt);
|
||||
if (IS_INTEGER(argv[1])) {
|
||||
CHECK_ARG(1,int,krk_integer_type,asInt);
|
||||
|
||||
if (asInt < 0) asInt += (long)self->length;
|
||||
if (asInt < 0 || asInt >= (long)self->length) {
|
||||
return krk_runtimeError(vm.exceptions->indexError, "bytes index out of range: %d", (int)asInt);
|
||||
}
|
||||
|
||||
return INTEGER_VAL(self->bytes[asInt]);
|
||||
|
||||
} else if (IS_slice(argv[1])) {
|
||||
KRK_SLICER(argv[1],self->length) {
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
if (step == 1) {
|
||||
krk_integer_type len = end - start;
|
||||
return OBJECT_VAL(krk_newBytes(len, &self->bytes[start]));
|
||||
} else {
|
||||
struct StringBuilder sb = {0};
|
||||
krk_integer_type i = start;
|
||||
while ((step < 0) ? (i > end) : (i < end)) {
|
||||
pushStringBuilder(&sb, self->bytes[i]);
|
||||
i += step;
|
||||
}
|
||||
return finishStringBuilderBytes(&sb);
|
||||
}
|
||||
} else {
|
||||
return TYPE_ERROR(int or slice, argv[1]);
|
||||
}
|
||||
|
||||
return INTEGER_VAL(self->bytes[asInt]);
|
||||
})
|
||||
|
||||
KRK_METHOD(bytes,__len__,{
|
||||
@ -186,25 +209,6 @@ 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__,{
|
||||
@ -295,14 +299,37 @@ KRK_METHOD(bytearray,__repr__,{
|
||||
|
||||
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 (IS_INTEGER(argv[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]);
|
||||
} else if (IS_slice(argv[1])) {
|
||||
KRK_SLICER(argv[1],AS_BYTES(self->actual)->length) {
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
if (step == 1) {
|
||||
krk_integer_type len = end - start;
|
||||
return OBJECT_VAL(krk_newBytes(len, &AS_BYTES(self->actual)->bytes[start]));
|
||||
} else {
|
||||
struct StringBuilder sb = {0};
|
||||
krk_integer_type i = start;
|
||||
while ((step < 0) ? (i > end) : (i < end)) {
|
||||
pushStringBuilder(&sb, AS_BYTES(self->actual)->bytes[i]);
|
||||
i += step;
|
||||
}
|
||||
return finishStringBuilderBytes(&sb);
|
||||
}
|
||||
|
||||
} else {
|
||||
return TYPE_ERROR(int or slice, argv[1]);
|
||||
}
|
||||
|
||||
return INTEGER_VAL(AS_BYTES(self->actual)->bytes[asInt]);
|
||||
})
|
||||
|
||||
KRK_METHOD(bytearray,__setitem__,{
|
||||
@ -337,25 +364,6 @@ KRK_METHOD(bytearray,decode,{
|
||||
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);
|
||||
@ -380,7 +388,6 @@ 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__);
|
||||
@ -408,7 +415,6 @@ void _createAndBind_bytesClass(void) {
|
||||
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);
|
||||
|
@ -88,8 +88,10 @@ KRK_METHOD(dict,__init__,{
|
||||
KRK_METHOD(dict,__getitem__,{
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
KrkValue out;
|
||||
if (!krk_tableGet(&self->entries, argv[1], &out))
|
||||
if (!krk_tableGet(&self->entries, argv[1], &out)) {
|
||||
if (!IS_NONE(krk_currentThread.currentException)) return NONE_VAL();
|
||||
KEY_ERROR(argv[1]);
|
||||
}
|
||||
return out;
|
||||
})
|
||||
|
||||
@ -112,6 +114,7 @@ KRK_METHOD(dict,__or__,{
|
||||
KRK_METHOD(dict,__delitem__,{
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
if (!krk_tableDelete(&self->entries, argv[1])) {
|
||||
if (!IS_NONE(krk_currentThread.currentException)) return NONE_VAL();
|
||||
KEY_ERROR(argv[1]);
|
||||
}
|
||||
})
|
||||
|
199
src/obj_list.c
199
src/obj_list.c
@ -49,22 +49,51 @@ KrkValue krk_list_of(int argc, KrkValue argv[], int hasKw) {
|
||||
|
||||
KRK_METHOD(list,__getitem__,{
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
CHECK_ARG(1,int,krk_integer_type,index);
|
||||
if (vm.globalFlags & KRK_GLOBAL_THREADS) pthread_rwlock_rdlock(&self->rwlock);
|
||||
LIST_WRAP_INDEX();
|
||||
KrkValue result = self->values.values[index];
|
||||
if (vm.globalFlags & KRK_GLOBAL_THREADS) pthread_rwlock_unlock(&self->rwlock);
|
||||
return result;
|
||||
})
|
||||
if (IS_INTEGER(argv[1])) {
|
||||
CHECK_ARG(1,int,krk_integer_type,index);
|
||||
if (vm.globalFlags & KRK_GLOBAL_THREADS) pthread_rwlock_rdlock(&self->rwlock);
|
||||
LIST_WRAP_INDEX();
|
||||
KrkValue result = self->values.values[index];
|
||||
if (vm.globalFlags & KRK_GLOBAL_THREADS) pthread_rwlock_unlock(&self->rwlock);
|
||||
return result;
|
||||
} else if (IS_slice(argv[1])) {
|
||||
pthread_rwlock_rdlock(&self->rwlock);
|
||||
|
||||
KRK_METHOD(list,__setitem__,{
|
||||
METHOD_TAKES_EXACTLY(2);
|
||||
CHECK_ARG(1,int,krk_integer_type,index);
|
||||
if (vm.globalFlags & KRK_GLOBAL_THREADS) pthread_rwlock_rdlock(&self->rwlock);
|
||||
LIST_WRAP_INDEX();
|
||||
self->values.values[index] = argv[2];
|
||||
if (vm.globalFlags & KRK_GLOBAL_THREADS) pthread_rwlock_unlock(&self->rwlock);
|
||||
return argv[2];
|
||||
KRK_SLICER(argv[1],self->values.count) {
|
||||
pthread_rwlock_unlock(&self->rwlock);
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
if (step == 1) {
|
||||
krk_integer_type len = end - start;
|
||||
KrkValue result = krk_list_of(len, &AS_LIST(argv[0])->values[start], 0);
|
||||
pthread_rwlock_unlock(&self->rwlock);
|
||||
return result;
|
||||
} else {
|
||||
/* iterate and push */
|
||||
krk_push(NONE_VAL());
|
||||
krk_integer_type len = 0;
|
||||
krk_integer_type i = start;
|
||||
while ((step < 0) ? (i > end) : (i < end)) {
|
||||
krk_push(self->values.values[i]);
|
||||
len++;
|
||||
i += step;
|
||||
}
|
||||
|
||||
/* make into a list */
|
||||
KrkValue result = krk_list_of(len, &krk_currentThread.stackTop[-len], 0);
|
||||
krk_currentThread.stackTop[-len-1] = result;
|
||||
while (len) {
|
||||
krk_pop();
|
||||
len--;
|
||||
}
|
||||
|
||||
pthread_rwlock_unlock(&self->rwlock);
|
||||
return krk_pop();
|
||||
}
|
||||
} else {
|
||||
return TYPE_ERROR(int or slice,argv[1]);
|
||||
}
|
||||
})
|
||||
|
||||
KRK_METHOD(list,__eq__,{
|
||||
@ -196,70 +225,6 @@ KRK_METHOD(list,__contains__,{
|
||||
return BOOLEAN_VAL(0);
|
||||
})
|
||||
|
||||
KRK_METHOD(list,__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]);
|
||||
pthread_rwlock_rdlock(&self->rwlock);
|
||||
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->values.count : AS_INTEGER(argv[2]);
|
||||
LIST_WRAP_SOFT(start);
|
||||
LIST_WRAP_SOFT(end);
|
||||
if (end < start) end = start;
|
||||
krk_integer_type len = end - start;
|
||||
|
||||
KrkValue result = krk_list_of(len, &AS_LIST(argv[0])->values[start], 0);
|
||||
pthread_rwlock_unlock(&self->rwlock);
|
||||
return result;
|
||||
})
|
||||
|
||||
FUNC_SIG(list,pop);
|
||||
KRK_METHOD(list,__delslice__,{
|
||||
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->values.count : AS_INTEGER(argv[2]);
|
||||
LIST_WRAP_SOFT(start);
|
||||
LIST_WRAP_SOFT(end);
|
||||
if (end < start) end = start;
|
||||
krk_integer_type len = end - start;
|
||||
|
||||
while (len > 0) {
|
||||
FUNC_NAME(list,pop)(2,(KrkValue[]){argv[0],INTEGER_VAL(start)},0);
|
||||
len--;
|
||||
}
|
||||
})
|
||||
|
||||
KRK_METHOD(list,__setslice__,{
|
||||
METHOD_TAKES_EXACTLY(3);
|
||||
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]);
|
||||
if (!IS_list(argv[3])) return TYPE_ERROR(list,argv[3]); /* TODO other sequence types */
|
||||
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->values.count : AS_INTEGER(argv[2]);
|
||||
LIST_WRAP_SOFT(start);
|
||||
LIST_WRAP_SOFT(end);
|
||||
if (end < start) end = start;
|
||||
krk_integer_type len = end - start;
|
||||
|
||||
krk_integer_type newLen = (krk_integer_type)AS_LIST(argv[3])->count;
|
||||
|
||||
for (krk_integer_type i = 0; (i < len && i < newLen); ++i) {
|
||||
AS_LIST(argv[0])->values[start+i] = AS_LIST(argv[3])->values[i];
|
||||
}
|
||||
|
||||
while (len < newLen) {
|
||||
FUNC_NAME(list,insert)(3, (KrkValue[]){argv[0], INTEGER_VAL(start + len), AS_LIST(argv[3])->values[len]}, 0);
|
||||
len++;
|
||||
}
|
||||
|
||||
while (newLen < len) {
|
||||
FUNC_NAME(list,pop)(2, (KrkValue[]){argv[0], INTEGER_VAL(start + len - 1)}, 0);
|
||||
len--;
|
||||
}
|
||||
})
|
||||
|
||||
KRK_METHOD(list,pop,{
|
||||
METHOD_TAKES_AT_MOST(1);
|
||||
pthread_rwlock_wrlock(&self->rwlock);
|
||||
@ -285,6 +250,77 @@ KRK_METHOD(list,pop,{
|
||||
}
|
||||
})
|
||||
|
||||
KRK_METHOD(list,__setitem__,{
|
||||
METHOD_TAKES_EXACTLY(2);
|
||||
if (IS_INTEGER(argv[1])) {
|
||||
CHECK_ARG(1,int,krk_integer_type,index);
|
||||
if (vm.globalFlags & KRK_GLOBAL_THREADS) pthread_rwlock_rdlock(&self->rwlock);
|
||||
LIST_WRAP_INDEX();
|
||||
self->values.values[index] = argv[2];
|
||||
if (vm.globalFlags & KRK_GLOBAL_THREADS) pthread_rwlock_unlock(&self->rwlock);
|
||||
return argv[2];
|
||||
} else if (IS_slice(argv[1])) {
|
||||
if (!IS_list(argv[2])) {
|
||||
return TYPE_ERROR(list,argv[2]); /* TODO other sequence types */
|
||||
}
|
||||
|
||||
KRK_SLICER(argv[1],self->values.count) {
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
if (step != 1) {
|
||||
return krk_runtimeError(vm.exceptions->valueError, "step value unsupported");
|
||||
}
|
||||
|
||||
krk_integer_type len = end - start;
|
||||
krk_integer_type newLen = (krk_integer_type)AS_LIST(argv[2])->count;
|
||||
|
||||
for (krk_integer_type i = 0; (i < len && i < newLen); ++i) {
|
||||
AS_LIST(argv[0])->values[start+i] = AS_LIST(argv[2])->values[i];
|
||||
}
|
||||
|
||||
while (len < newLen) {
|
||||
FUNC_NAME(list,insert)(3, (KrkValue[]){argv[0], INTEGER_VAL(start + len), AS_LIST(argv[2])->values[len]}, 0);
|
||||
len++;
|
||||
}
|
||||
|
||||
while (newLen < len) {
|
||||
FUNC_NAME(list,pop)(2, (KrkValue[]){argv[0], INTEGER_VAL(start + len - 1)}, 0);
|
||||
len--;
|
||||
}
|
||||
|
||||
return OBJECT_VAL(self);
|
||||
} else {
|
||||
return TYPE_ERROR(int or slice, argv[1]);
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
KRK_METHOD(list,__delitem__,{
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
|
||||
if (IS_INTEGER(argv[1])) {
|
||||
FUNC_NAME(list,pop)(2,(KrkValue[]){argv[0],INTEGER_VAL(argv[1])},0);
|
||||
} else if (IS_slice(argv[1])) {
|
||||
KRK_SLICER(argv[1],self->values.count) {
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
if (step != 1) {
|
||||
return krk_runtimeError(vm.exceptions->valueError, "step value unsupported");
|
||||
}
|
||||
|
||||
krk_integer_type len = end - start;
|
||||
|
||||
while (len > 0) {
|
||||
FUNC_NAME(list,pop)(2,(KrkValue[]){argv[0],INTEGER_VAL(start)},0);
|
||||
len--;
|
||||
}
|
||||
} else {
|
||||
return TYPE_ERROR(int or slice, argv[1]);
|
||||
}
|
||||
})
|
||||
|
||||
KRK_METHOD(list,remove,{
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
pthread_rwlock_wrlock(&self->rwlock);
|
||||
@ -486,12 +522,10 @@ void _createAndBind_listClass(void) {
|
||||
BIND_METHOD(list,__eq__);
|
||||
BIND_METHOD(list,__getitem__);
|
||||
BIND_METHOD(list,__setitem__);
|
||||
BIND_METHOD(list,__delitem__);
|
||||
BIND_METHOD(list,__len__);
|
||||
BIND_METHOD(list,__repr__);
|
||||
BIND_METHOD(list,__contains__);
|
||||
BIND_METHOD(list,__getslice__);
|
||||
BIND_METHOD(list,__delslice__);
|
||||
BIND_METHOD(list,__setslice__);
|
||||
BIND_METHOD(list,__iter__);
|
||||
BIND_METHOD(list,__mul__);
|
||||
BIND_METHOD(list,__add__);
|
||||
@ -546,7 +580,6 @@ void _createAndBind_listClass(void) {
|
||||
"@brief Sort the contents of a list.\n\n"
|
||||
"Performs an in-place sort of the elements in the list, returning @c None as a gentle reminder "
|
||||
"that the sort is in-place. If a sorted copy is desired, use @ref sorted instead.");
|
||||
krk_defineNative(&list->methods, "__delitem__", FUNC_NAME(list,pop));
|
||||
krk_defineNative(&list->methods, "__str__", FUNC_NAME(list,__repr__));
|
||||
krk_defineNative(&list->methods, "__class_getitem__", KrkGenericAlias)->flags |= KRK_NATIVE_FLAGS_IS_CLASS_METHOD;
|
||||
krk_attachNamedValue(&list->methods, "__hash__", NONE_VAL());
|
||||
|
181
src/obj_slice.c
Normal file
181
src/obj_slice.c
Normal file
@ -0,0 +1,181 @@
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <kuroko/vm.h>
|
||||
#include <kuroko/value.h>
|
||||
#include <kuroko/memory.h>
|
||||
#include <kuroko/util.h>
|
||||
|
||||
static void _slice_gcscan(KrkInstance * self) {
|
||||
krk_markValue(((struct KrkSlice*)self)->start);
|
||||
krk_markValue(((struct KrkSlice*)self)->end);
|
||||
krk_markValue(((struct KrkSlice*)self)->step);
|
||||
}
|
||||
|
||||
KrkValue krk_slice_of(int argc, KrkValue argv[], int hasKw) {
|
||||
KrkValue outSlice = OBJECT_VAL(krk_newInstance(vm.baseClasses->sliceClass));
|
||||
krk_push(outSlice);
|
||||
|
||||
AS_slice(outSlice)->start = (argc > 0) ? argv[0] : NONE_VAL();
|
||||
AS_slice(outSlice)->end = (argc > 1) ? argv[1] : NONE_VAL();
|
||||
AS_slice(outSlice)->step = (argc > 2) ? argv[2] : NONE_VAL();
|
||||
|
||||
return krk_pop();
|
||||
}
|
||||
|
||||
static inline krk_integer_type _wrap(krk_integer_type count, krk_integer_type val) {
|
||||
if (val < 0) val += count;
|
||||
if (val < 0) val = 0;
|
||||
if (val > count) val = count;
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline krk_integer_type _wrapn(krk_integer_type count, krk_integer_type val) {
|
||||
if (val < 0) val += count;
|
||||
if (val < -1) val = -1;
|
||||
if (val > count) val = count;
|
||||
return val;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!(IS_slice(slicerVal))) {
|
||||
TYPE_ERROR(slice, slicerVal);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct KrkSlice * slicer = AS_slice(slicerVal);
|
||||
|
||||
KrkValue _start = slicer->start;
|
||||
KrkValue _end = slicer->end;
|
||||
KrkValue _step = slicer->step;
|
||||
|
||||
if (!(IS_INTEGER(_start) || IS_NONE(_start))) {
|
||||
TYPE_ERROR(int or None, _start);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(IS_INTEGER(_end) || IS_NONE(_end))) {
|
||||
TYPE_ERROR(int or None, _end);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(IS_INTEGER(_step) || IS_NONE(_step))) {
|
||||
TYPE_ERROR(int or None, _step);
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
*start = 0;
|
||||
*end = 0;
|
||||
*step = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* First off, the step */
|
||||
*step = IS_NONE(_step) ? 1 : AS_INTEGER(_step);
|
||||
|
||||
if (*step == 0) {
|
||||
krk_runtimeError(vm.exceptions->valueError, "invalid 0 step");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (*step > 0) {
|
||||
/* Normal step bounds */
|
||||
*start = _wrap(count, IS_NONE(_start) ? 0 : AS_INTEGER(_start));
|
||||
*end = _wrap(count, IS_NONE(_end) ? count : AS_INTEGER(_end));
|
||||
if (*end < *start) *end = *start;
|
||||
} else {
|
||||
*start = IS_NONE(_start) ? (count-1) : _wrap(count, AS_INTEGER(_start));
|
||||
if (*start >= count) *start = count -1;
|
||||
*end = IS_NONE(_end) ? -1 : _wrapn(count, AS_INTEGER(_end));
|
||||
if (*end > *start) *end = *start;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CURRENT_CTYPE struct KrkSlice *
|
||||
#define CURRENT_NAME self
|
||||
|
||||
KRK_METHOD(slice,__init__,{
|
||||
METHOD_TAKES_AT_LEAST(1);
|
||||
METHOD_TAKES_AT_MOST(3);
|
||||
|
||||
if (argc == 2) {
|
||||
self->start = NONE_VAL();
|
||||
self->end = argv[1];
|
||||
self->step = NONE_VAL();
|
||||
} else {
|
||||
self->start = argv[1];
|
||||
self->end = argv[2];
|
||||
if (argc > 3) {
|
||||
self->step = argv[3];
|
||||
} else {
|
||||
self->step = NONE_VAL();
|
||||
}
|
||||
}
|
||||
return argv[0];
|
||||
})
|
||||
|
||||
KRK_METHOD(slice,__repr__,{
|
||||
METHOD_TAKES_NONE();
|
||||
if (((KrkObj*)self)->flags & KRK_OBJ_FLAGS_IN_REPR) return OBJECT_VAL("slice(...)");
|
||||
((KrkObj*)self)->flags |= KRK_OBJ_FLAGS_IN_REPR;
|
||||
struct StringBuilder sb = {0};
|
||||
pushStringBuilderStr(&sb,"slice(",6);
|
||||
|
||||
KrkClass * type;
|
||||
KrkValue result;
|
||||
|
||||
/* start */
|
||||
type = krk_getType(self->start);
|
||||
krk_push(self->start);
|
||||
result = krk_callDirect(type->_reprer, 1);
|
||||
if (IS_STRING(result)) pushStringBuilderStr(&sb, AS_STRING(result)->chars, AS_STRING(result)->length);
|
||||
pushStringBuilderStr(&sb,", ",2);
|
||||
|
||||
/* end */
|
||||
type = krk_getType(self->end);
|
||||
krk_push(self->end);
|
||||
result = krk_callDirect(type->_reprer, 1);
|
||||
if (IS_STRING(result)) pushStringBuilderStr(&sb, AS_STRING(result)->chars, AS_STRING(result)->length);
|
||||
pushStringBuilderStr(&sb,", ",2);
|
||||
|
||||
/* step */
|
||||
type = krk_getType(self->step);
|
||||
krk_push(self->step);
|
||||
result = krk_callDirect(type->_reprer, 1);
|
||||
if (IS_STRING(result)) pushStringBuilderStr(&sb, AS_STRING(result)->chars, AS_STRING(result)->length);
|
||||
|
||||
pushStringBuilder(&sb,')');
|
||||
((KrkObj*)self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
|
||||
return finishStringBuilder(&sb);
|
||||
})
|
||||
|
||||
KRK_METHOD(slice,start,{
|
||||
ATTRIBUTE_NOT_ASSIGNABLE();
|
||||
return self->start;
|
||||
})
|
||||
|
||||
KRK_METHOD(slice,end,{
|
||||
ATTRIBUTE_NOT_ASSIGNABLE();
|
||||
return self->end;
|
||||
})
|
||||
|
||||
KRK_METHOD(slice,step,{
|
||||
ATTRIBUTE_NOT_ASSIGNABLE();
|
||||
return self->step;
|
||||
})
|
||||
|
||||
_noexport
|
||||
void _createAndBind_sliceClass(void) {
|
||||
KrkClass * slice = ADD_BASE_CLASS(vm.baseClasses->sliceClass, "slice", vm.baseClasses->objectClass);
|
||||
slice->allocSize = sizeof(struct KrkSlice);
|
||||
slice->_ongcscan = _slice_gcscan;
|
||||
BIND_METHOD(slice,__init__);
|
||||
BIND_METHOD(slice,__repr__);
|
||||
BIND_PROP(slice,start);
|
||||
BIND_PROP(slice,end);
|
||||
BIND_PROP(slice,step);
|
||||
krk_defineNative(&slice->methods, "__str__", FUNC_NAME(slice,__repr__));
|
||||
krk_attachNamedValue(&slice->methods, "__hash__", NONE_VAL());
|
||||
krk_finalizeClass(slice);
|
||||
}
|
106
src/obj_str.c
106
src/obj_str.c
@ -90,46 +90,6 @@ KRK_METHOD(str,__setitem__,{
|
||||
return krk_runtimeError(vm.exceptions->typeError, "Strings are not mutable.");
|
||||
})
|
||||
|
||||
/**
|
||||
* Unlike in Python, we actually handle negative values here rather than
|
||||
* somewhere else? I'm not even sure where Python does do it, but a quick
|
||||
* says not if you call __getslice__ directly...
|
||||
*/
|
||||
KRK_METHOD(str,__getslice__,{
|
||||
METHOD_TAKES_EXACTLY(2);
|
||||
if (!(IS_INTEGER(argv[1]) || IS_NONE(argv[1])))
|
||||
return TYPE_ERROR(int,argv[1]);
|
||||
if (!(IS_INTEGER(argv[2]) || IS_NONE(argv[2])))
|
||||
return TYPE_ERROR(int,argv[2]);
|
||||
/* bounds check */
|
||||
long start = IS_NONE(argv[1]) ? 0 : AS_INTEGER(argv[1]);
|
||||
long end = IS_NONE(argv[2]) ? (long)self->codesLength : AS_INTEGER(argv[2]);
|
||||
if (start < 0) start = self->codesLength + start;
|
||||
if (start < 0) start = 0;
|
||||
if (end < 0) end = self->codesLength + end;
|
||||
if (start > (long)self->codesLength) start = self->codesLength;
|
||||
if (end > (long)self->codesLength) end = self->codesLength;
|
||||
if (end < start) end = start;
|
||||
long len = end - start;
|
||||
if (self->type == KRK_STRING_ASCII) {
|
||||
return OBJECT_VAL(krk_copyString(self->chars + start, len));
|
||||
} else {
|
||||
size_t offset = 0;
|
||||
size_t length = 0;
|
||||
/* Figure out where the UTF8 for this string starts. */
|
||||
krk_unicodeString(self);
|
||||
for (long i = 0; i < start; ++i) {
|
||||
uint32_t cp = KRK_STRING_FAST(self,i);
|
||||
offset += CODEPOINT_BYTES(cp);
|
||||
}
|
||||
for (long i = start; i < end; ++i) {
|
||||
uint32_t cp = KRK_STRING_FAST(self,i);
|
||||
length += CODEPOINT_BYTES(cp);
|
||||
}
|
||||
return OBJECT_VAL(krk_copyString(self->chars + offset, length));
|
||||
}
|
||||
})
|
||||
|
||||
/* str.__int__(base=10) */
|
||||
KRK_METHOD(str,__int__,{
|
||||
METHOD_TAKES_AT_MOST(1);
|
||||
@ -159,18 +119,61 @@ KRK_METHOD(str,__float__,{
|
||||
|
||||
KRK_METHOD(str,__getitem__,{
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
CHECK_ARG(1,int,krk_integer_type,asInt);
|
||||
if (asInt < 0) asInt += (int)AS_STRING(argv[0])->codesLength;
|
||||
if (asInt < 0 || asInt >= (int)AS_STRING(argv[0])->codesLength) {
|
||||
return krk_runtimeError(vm.exceptions->indexError, "String index out of range: " PRIkrk_int, asInt);
|
||||
}
|
||||
if (self->type == KRK_STRING_ASCII) {
|
||||
return OBJECT_VAL(krk_copyString(self->chars + asInt, 1));
|
||||
if (IS_INTEGER(argv[1])) {
|
||||
CHECK_ARG(1,int,krk_integer_type,asInt);
|
||||
if (asInt < 0) asInt += (int)AS_STRING(argv[0])->codesLength;
|
||||
if (asInt < 0 || asInt >= (int)AS_STRING(argv[0])->codesLength) {
|
||||
return krk_runtimeError(vm.exceptions->indexError, "String index out of range: " PRIkrk_int, asInt);
|
||||
}
|
||||
if (self->type == KRK_STRING_ASCII) {
|
||||
return OBJECT_VAL(krk_copyString(self->chars + asInt, 1));
|
||||
} else {
|
||||
krk_unicodeString(self);
|
||||
unsigned char asbytes[5];
|
||||
size_t length = krk_codepointToBytes(KRK_STRING_FAST(self,asInt),(unsigned char*)&asbytes);
|
||||
return OBJECT_VAL(krk_copyString((char*)&asbytes, length));
|
||||
}
|
||||
} else if (IS_slice(argv[1])) {
|
||||
KRK_SLICER(argv[1], self->codesLength) {
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
if (step == 1) {
|
||||
long len = end - start;
|
||||
if (self->type == KRK_STRING_ASCII) {
|
||||
return OBJECT_VAL(krk_copyString(self->chars + start, len));
|
||||
} else {
|
||||
size_t offset = 0;
|
||||
size_t length = 0;
|
||||
/* Figure out where the UTF8 for this string starts. */
|
||||
krk_unicodeString(self);
|
||||
for (long i = 0; i < start; ++i) {
|
||||
uint32_t cp = KRK_STRING_FAST(self,i);
|
||||
offset += CODEPOINT_BYTES(cp);
|
||||
}
|
||||
for (long i = start; i < end; ++i) {
|
||||
uint32_t cp = KRK_STRING_FAST(self,i);
|
||||
length += CODEPOINT_BYTES(cp);
|
||||
}
|
||||
return OBJECT_VAL(krk_copyString(self->chars + offset, length));
|
||||
}
|
||||
} else {
|
||||
struct StringBuilder sb = {0};
|
||||
krk_unicodeString(self);
|
||||
|
||||
unsigned char asbytes[5];
|
||||
krk_integer_type i = start;
|
||||
|
||||
while ((step < 0) ? (i > end) : (i < end)) {
|
||||
size_t length = krk_codepointToBytes(KRK_STRING_FAST(self,i),(unsigned char*)&asbytes);
|
||||
pushStringBuilderStr(&sb, (char*)asbytes, length);
|
||||
i += step;
|
||||
}
|
||||
|
||||
return finishStringBuilder(&sb);
|
||||
}
|
||||
} else {
|
||||
krk_unicodeString(self);
|
||||
unsigned char asbytes[5];
|
||||
size_t length = krk_codepointToBytes(KRK_STRING_FAST(self,asInt),(unsigned char*)&asbytes);
|
||||
return OBJECT_VAL(krk_copyString((char*)&asbytes, length));
|
||||
return TYPE_ERROR(int or slice, argv[1]);
|
||||
}
|
||||
})
|
||||
|
||||
@ -885,7 +888,6 @@ void _createAndBind_strClass(void) {
|
||||
BIND_METHOD(str,__ord__);
|
||||
BIND_METHOD(str,__int__);
|
||||
BIND_METHOD(str,__float__);
|
||||
BIND_METHOD(str,__getslice__);
|
||||
BIND_METHOD(str,__getitem__);
|
||||
BIND_METHOD(str,__setitem__);
|
||||
BIND_METHOD(str,__add__);
|
||||
|
@ -62,9 +62,43 @@ KRK_METHOD(tuple,__len__,{
|
||||
|
||||
KRK_METHOD(tuple,__getitem__,{
|
||||
METHOD_TAKES_EXACTLY(1);
|
||||
CHECK_ARG(1,int,krk_integer_type,index);
|
||||
TUPLE_WRAP_INDEX();
|
||||
return self->values.values[index];
|
||||
if (IS_INTEGER(argv[1])) {
|
||||
CHECK_ARG(1,int,krk_integer_type,index);
|
||||
TUPLE_WRAP_INDEX();
|
||||
return self->values.values[index];
|
||||
} else if (IS_slice(argv[1])) {
|
||||
KRK_SLICER(argv[1],self->values.count) {
|
||||
return NONE_VAL();
|
||||
}
|
||||
|
||||
if (step == 1) {
|
||||
krk_integer_type len = end - start;
|
||||
KrkValue result = krk_tuple_of(len, &self->values.values[start], 0);
|
||||
return result;
|
||||
} else {
|
||||
/* iterate and push */
|
||||
krk_push(NONE_VAL());
|
||||
krk_integer_type len = 0;
|
||||
krk_integer_type i = start;
|
||||
while ((step < 0) ? (i > end) : (i < end)) {
|
||||
krk_push(self->values.values[i]);
|
||||
len++;
|
||||
i += step;
|
||||
}
|
||||
|
||||
/* make into a list */
|
||||
KrkValue result = krk_tuple_of(len, &krk_currentThread.stackTop[-len], 0);
|
||||
krk_currentThread.stackTop[-len-1] = result;
|
||||
while (len) {
|
||||
krk_pop();
|
||||
len--;
|
||||
}
|
||||
|
||||
return krk_pop();
|
||||
}
|
||||
} else {
|
||||
return TYPE_ERROR(int or slice, argv[1]);
|
||||
}
|
||||
})
|
||||
|
||||
KRK_METHOD(tuple,__eq__,{
|
||||
|
@ -26,9 +26,6 @@ SIMPLE(OP_BITNEGATE)
|
||||
SIMPLE(OP_INVOKE_GETTER)
|
||||
SIMPLE(OP_INVOKE_SETTER)
|
||||
SIMPLE(OP_INVOKE_DELETE)
|
||||
SIMPLE(OP_INVOKE_GETSLICE)
|
||||
SIMPLE(OP_INVOKE_SETSLICE)
|
||||
SIMPLE(OP_INVOKE_DELSLICE)
|
||||
SIMPLE(OP_INVOKE_ITER)
|
||||
SIMPLE(OP_INVOKE_CONTAINS)
|
||||
SIMPLE(OP_INVOKE_AWAIT)
|
||||
@ -78,6 +75,7 @@ OPERAND(OP_MAKE_LIST, (void)0)
|
||||
OPERAND(OP_MAKE_DICT, (void)0)
|
||||
OPERAND(OP_MAKE_SET, (void)0)
|
||||
OPERAND(OP_REVERSE, (void)0)
|
||||
OPERAND(OP_SLICE, (void)0)
|
||||
JUMP(OP_JUMP_IF_FALSE_OR_POP,+)
|
||||
JUMP(OP_JUMP_IF_TRUE_OR_POP,+)
|
||||
JUMP(OP_JUMP,+)
|
||||
|
@ -17,6 +17,7 @@ extern void _createAndBind_functionClass(void);
|
||||
extern void _createAndBind_rangeClass(void);
|
||||
extern void _createAndBind_setClass(void);
|
||||
extern void _createAndBind_generatorClass(void);
|
||||
extern void _createAndBind_sliceClass(void);
|
||||
extern void _createAndBind_builtins(void);
|
||||
extern void _createAndBind_type(void);
|
||||
extern void _createAndBind_exceptions(void);
|
||||
|
@ -50,7 +50,8 @@ inline int krk_hashValue(KrkValue value, uint32_t *hashOut) {
|
||||
return 0;
|
||||
}
|
||||
_unhashable:
|
||||
krk_runtimeError(vm.exceptions->typeError, "unhashable type: '%s'", krk_typeName(value));
|
||||
if (IS_NONE(krk_currentThread.currentException))
|
||||
krk_runtimeError(vm.exceptions->typeError, "unhashable type: '%s'", krk_typeName(value));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
2
src/vendor/rline.c
vendored
2
src/vendor/rline.c
vendored
@ -559,7 +559,7 @@ char * syn_krk_types[] = {
|
||||
"print","set","any","all","bool","ord","chr","hex","oct","filter",
|
||||
"sorted","bytes","getattr","sum","min","max","id","hash","map","bin",
|
||||
"enumerate","zip","setattr","property","staticmethod","classmethod",
|
||||
"issubclass","hasattr","delattr","NotImplemented","abs",
|
||||
"issubclass","hasattr","delattr","NotImplemented","abs","slice",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
42
src/vm.c
42
src/vm.c
@ -392,9 +392,6 @@ void krk_finalizeClass(KrkClass * _class) {
|
||||
struct TypeMap specials[] = {
|
||||
{&_class->_getter, METHOD_GET},
|
||||
{&_class->_setter, METHOD_SET},
|
||||
{&_class->_getslice, METHOD_GETSLICE},
|
||||
{&_class->_setslice, METHOD_SETSLICE},
|
||||
{&_class->_delslice, METHOD_DELSLICE},
|
||||
{&_class->_reprer, METHOD_REPR},
|
||||
{&_class->_tostr, METHOD_STR},
|
||||
{&_class->_call, METHOD_CALL},
|
||||
@ -1199,10 +1196,6 @@ void krk_initVM(int flags) {
|
||||
_(METHOD_GET, "__getitem__"),
|
||||
_(METHOD_SET, "__setitem__"),
|
||||
_(METHOD_DELITEM, "__delitem__"),
|
||||
/* Slice subscripting */
|
||||
_(METHOD_GETSLICE, "__getslice__"),
|
||||
_(METHOD_SETSLICE, "__setslice__"),
|
||||
_(METHOD_DELSLICE, "__delslice__"),
|
||||
/* Dynamic properties */
|
||||
_(METHOD_CLASS, "__class__"),
|
||||
_(METHOD_NAME, "__name__"),
|
||||
@ -1251,6 +1244,7 @@ void krk_initVM(int flags) {
|
||||
_createAndBind_functionClass();
|
||||
_createAndBind_rangeClass();
|
||||
_createAndBind_setClass();
|
||||
_createAndBind_sliceClass();
|
||||
_createAndBind_exceptions();
|
||||
_createAndBind_generatorClass();
|
||||
_createAndBind_gcMod();
|
||||
@ -2246,33 +2240,6 @@ _finishReturn: (void)0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OP_INVOKE_GETSLICE: {
|
||||
KrkClass * type = krk_getType(krk_peek(2));
|
||||
if (likely(type->_getslice != NULL)) {
|
||||
krk_push(krk_callDirect(type->_getslice, 3));
|
||||
} else {
|
||||
krk_runtimeError(vm.exceptions->attributeError, "'%s' object is not sliceable", krk_typeName(krk_peek(2)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OP_INVOKE_SETSLICE: {
|
||||
KrkClass * type = krk_getType(krk_peek(3));
|
||||
if (likely(type->_setslice != NULL)) {
|
||||
krk_push(krk_callDirect(type->_setslice, 4));
|
||||
} else {
|
||||
krk_runtimeError(vm.exceptions->attributeError, "'%s' object is not sliceable", krk_typeName(krk_peek(3)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OP_INVOKE_DELSLICE: {
|
||||
KrkClass * type = krk_getType(krk_peek(2));
|
||||
if (likely(type->_delslice != NULL)) {
|
||||
krk_callDirect(type->_delslice, 3);
|
||||
} else {
|
||||
krk_runtimeError(vm.exceptions->attributeError, "'%s' object is not sliceable", krk_typeName(krk_peek(2)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OP_INVOKE_DELETE: {
|
||||
KrkClass * type = krk_getType(krk_peek(1));
|
||||
if (likely(type->_delitem != NULL)) {
|
||||
@ -2824,6 +2791,13 @@ _finishReturn: (void)0;
|
||||
doMake(krk_set_of);
|
||||
break;
|
||||
}
|
||||
case OP_SLICE_LONG:
|
||||
THREE_BYTE_OPERAND;
|
||||
case OP_SLICE: {
|
||||
ONE_BYTE_OPERAND;
|
||||
doMake(krk_slice_of);
|
||||
break;
|
||||
}
|
||||
case OP_LIST_APPEND_LONG:
|
||||
THREE_BYTE_OPERAND;
|
||||
case OP_LIST_APPEND: {
|
||||
|
34
test/testSlicers.krk
Normal file
34
test/testSlicers.krk
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
|
||||
def test(a):
|
||||
print(a[::])
|
||||
print(a[::-1])
|
||||
print(a[::2])
|
||||
print(a[::-2])
|
||||
print(a[1:2])
|
||||
print(a[1:7:3])
|
||||
print(a[5::-3])
|
||||
|
||||
|
||||
test([1,2,3,4,5,6,7,8,9,10,11,12,13])
|
||||
|
||||
test("こんにちは、みんなさま。クロコへようこそ。")
|
||||
|
||||
|
||||
class SlicerTester:
|
||||
def __getitem__(self, indexer):
|
||||
print(indexer)
|
||||
|
||||
|
||||
SlicerTester()[::]
|
||||
SlicerTester()[::-1]
|
||||
SlicerTester()[1:2:3]
|
||||
SlicerTester()['a':'b':'c']
|
||||
SlicerTester()[:]
|
||||
SlicerTester()[:'end']
|
||||
SlicerTester()['start':]
|
||||
SlicerTester()[:'end':]
|
||||
SlicerTester()[:'end':'step']
|
||||
SlicerTester()['start'::'step']
|
||||
SlicerTester()[1:2,3:4]
|
||||
SlicerTester()[1:2:3,::4]
|
26
test/testSlicers.krk.expect
Normal file
26
test/testSlicers.krk.expect
Normal file
@ -0,0 +1,26 @@
|
||||
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
||||
[13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
|
||||
[1, 3, 5, 7, 9, 11, 13]
|
||||
[13, 11, 9, 7, 5, 3, 1]
|
||||
[2]
|
||||
[2, 5]
|
||||
[6, 3]
|
||||
こんにちは、みんなさま。クロコへようこそ。
|
||||
。そこうよへコロク。まさなんみ、はちにんこ
|
||||
こにはみなまクコよこ。
|
||||
。こよコクまなみはにこ
|
||||
ん
|
||||
んは
|
||||
、に
|
||||
slice(None, None, None)
|
||||
slice(None, None, -1)
|
||||
slice(1, 2, 3)
|
||||
slice('a', 'b', 'c')
|
||||
slice(None, None, None)
|
||||
slice(None, 'end', None)
|
||||
slice('start', None, None)
|
||||
slice(None, 'end', None)
|
||||
slice(None, 'end', 'step')
|
||||
slice('start', None, 'step')
|
||||
(slice(1, 2, None), slice(3, 4, None))
|
||||
(slice(1, 2, 3), slice(None, None, 4))
|
Loading…
Reference in New Issue
Block a user