Oops, fix strings; simplify bytecode around getters/setters; use this approach for slicing

This commit is contained in:
K. Lange 2021-01-04 18:10:55 +09:00
parent 49b7eb2941
commit b93429d6a6
4 changed files with 35 additions and 18 deletions

View File

@ -484,6 +484,7 @@ static void assignmentValue(void) {
static void get_(int canAssign) {
int isSlice = 0;
emitBytes(OP_DUP, 0);
if (match(TOKEN_COLON)) {
emitByte(OP_NONE);
isSlice = 1;
@ -512,11 +513,12 @@ static void get_(int canAssign) {
expression();
emitByte(OP_INVOKE_SETTER);
} else if (canAssign && matchAssignment()) {
emitByte(OP_SWAP);
emitBytes(OP_DUP, 1);
emitByte(OP_INVOKE_GETTER);
assignmentValue();
emitByte(OP_INVOKE_SETTER);
emitBytes(OP_DUP, 1); /* o o e o */
emitBytes(OP_DUP, 0); /* o o e o o */
emitBytes(OP_DUP, 2); /* o o e o o e */
emitByte(OP_INVOKE_GETTER); /* o o e v */
assignmentValue(); /* o o e v a */
emitByte(OP_INVOKE_SETTER); /* r */
} else {
emitByte(OP_INVOKE_GETTER);
}

View File

@ -121,6 +121,7 @@ KrkInstance * krk_newInstance(KrkClass * _class) {
instance->_getter = NULL;
instance->_setter = NULL;
instance->_slicer = NULL;
KrkValue tmp;
if (krk_tableGet(&_class->methods, vm.specialMethodNames[METHOD_GET], &tmp)) {
@ -129,6 +130,9 @@ KrkInstance * krk_newInstance(KrkClass * _class) {
if (krk_tableGet(&_class->methods, vm.specialMethodNames[METHOD_SET], &tmp)) {
instance->_setter = AS_OBJECT(tmp);
}
if (krk_tableGet(&_class->methods, vm.specialMethodNames[METHOD_GETSLICE], &tmp)) {
instance->_slicer = AS_OBJECT(tmp);
}
return instance;
}

View File

@ -89,8 +89,11 @@ typedef struct {
KrkObj obj;
KrkClass * _class;
KrkTable fields;
/* Quick access for common stuff */
KrkObj * _getter;
KrkObj * _setter;
KrkObj * _slicer;
} KrkInstance;
typedef struct {

34
vm.c
View File

@ -2845,9 +2845,13 @@ static KrkValue run() {
}
case OP_INVOKE_GETTER: {
if (IS_INSTANCE(krk_peek(1)) && AS_INSTANCE(krk_peek(1))->_getter) {
krk_push(krk_peek(0));
vm.stackTop[-2] = krk_peek(2);
krk_push(krk_callSimple(OBJECT_VAL(AS_INSTANCE(krk_peek(2))->_getter), 2));
} else if (IS_STRING(krk_peek(1))) {
KrkValue out = _string_get(2, (KrkValue[]){krk_peek(1), krk_peek(0)});
krk_pop(); /* index */
krk_pop(); /* base object */
krk_pop(); /* duplicate for binds */
krk_push(out); /* result */
} else {
krk_runtimeError(vm.exceptions.attributeError, "'%s' object is not subscriptable", krk_typeName(krk_peek(0)));
}
@ -2855,25 +2859,29 @@ static KrkValue run() {
}
case OP_INVOKE_SETTER: {
if (IS_INSTANCE(krk_peek(2)) && AS_INSTANCE(krk_peek(2))->_setter) {
krk_push(krk_peek(0));
vm.stackTop[-2] = krk_peek(2);
vm.stackTop[-3] = krk_peek(3);
KrkValue result = krk_callSimple(OBJECT_VAL(AS_INSTANCE(krk_peek(3))->_setter), 3);
krk_push(result);
} else if (IS_STRING(krk_peek(2))) {
_strings_are_immutable(0,NULL);
goto _finishException;
} else {
krk_runtimeError(vm.exceptions.attributeError, "'%s' object is not subscriptable", krk_typeName(krk_peek(0)));
}
break;
}
case OP_INVOKE_GETSLICE: {
krk_push(krk_peek(2)); /* object to top */
valueGetProperty(AS_STRING(vm.specialMethodNames[METHOD_GETSLICE]));
krk_swap(3);
krk_pop();
switch (krk_callValue(krk_peek(2),2,1)) {
case 2: break;
case 1: krk_push(krk_runNext()); break;
default: krk_runtimeError(vm.exceptions.typeError, "Invalid method call."); goto _finishException;
if (IS_INSTANCE(krk_peek(2)) && AS_INSTANCE(krk_peek(2))->_slicer) {
KrkValue result = krk_callSimple(OBJECT_VAL(AS_INSTANCE(krk_peek(3))->_slicer), 3);
krk_push(result);
} else if (IS_STRING(krk_peek(2))) {
KrkValue out = _string_get_slice(3, (KrkValue[]){krk_peek(2), krk_peek(1), krk_peek(0)});
krk_pop(); /* max */
krk_pop(); /* min */
krk_pop(); /* base object */
krk_pop(); /* duplicate for binds */
krk_push(out); /* result */
} else {
krk_runtimeError(vm.exceptions.attributeError, "'%s' object is not sliceable", krk_typeName(krk_peek(0)));
}
break;
}