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

View File

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

View File

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

34
vm.c
View File

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