From 617d30d804321c4e1c9d9ec446bf1e3f11b0e75b Mon Sep 17 00:00:00 2001 From: "K. Lange" Date: Wed, 25 Jan 2023 22:10:13 +0900 Subject: [PATCH] Very initial rebuild of class creation --- src/builtins.c | 95 ++++++++++++++++++++++ src/compiler.c | 114 ++++++++++++++++++++------- src/kuroko/object.h | 4 +- src/kuroko/util.h | 2 +- src/memory.c | 1 - src/obj_base.c | 11 +-- src/opcodes.h | 5 +- src/vm.c | 93 ++++++++-------------- test/testAnnotations.krk.expect | 2 +- test/testAttributePacking.krk.expect | 2 +- test/testDel.krk.expect | 6 +- test/testGetattrDir.krk.expect | 4 +- 12 files changed, 225 insertions(+), 114 deletions(-) diff --git a/src/builtins.c b/src/builtins.c index f2e3c2c..47c256f 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1241,6 +1241,98 @@ static void module_sweep(KrkInstance * inst) { #endif } +/** + * This should really be the default behavior of type.__new__? + */ +static void _callSetName(KrkClass * _class) { + KrkValue setnames = krk_list_of(0,NULL,0); + krk_push(setnames); + extern FUNC_SIG(list,append); + + /* The semantics of this require that we first collect all of the relevant items... */ + for (size_t i = 0; i < _class->methods.capacity; ++i) { + KrkTableEntry * entry = &_class->methods.entries[i]; + if (!IS_KWARGS(entry->key)) { + KrkClass * type = krk_getType(entry->value); + if (type->_set_name) { + FUNC_NAME(list,append)(2,(KrkValue[]){setnames,entry->key},0); + FUNC_NAME(list,append)(2,(KrkValue[]){setnames,entry->value},0); + } + } + } + + /* Then call __set_name__ on them */ + for (size_t i = 0; i < AS_LIST(setnames)->count; i += 2) { + KrkValue name = AS_LIST(setnames)->values[i]; + KrkValue value = AS_LIST(setnames)->values[i+1]; + KrkClass * type = krk_getType(value); + if (type->_set_name) { + krk_push(value); + krk_push(OBJECT_VAL(_class)); + krk_push(name); + krk_callDirect(type->_set_name, 3); + + /* If any of these raises an exception, bail; CPython raises + * an outer exception, setting the cause, but I'm being lazy + * at the moment... */ + if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) { + break; + } + } + } + + /* List used to store name+value pairs */ + krk_pop(); +} + + +KRK_Function(__build_class__) { + KrkValue func = NONE_VAL(); + KrkString * name = NULL; + KrkClass * base = vm.baseClasses->objectClass; + KrkValue metaclass = OBJECT_VAL(vm.baseClasses->typeClass); + + if (!krk_parseArgs("VO!|O!$V~", + (const char*[]){"func","name","base","metaclass"}, + &func, + vm.baseClasses->strClass, &name, + vm.baseClasses->typeClass, &base, + &metaclass)) { + return NONE_VAL(); + } + + /* Push function */ + krk_push(func); + + /* Dict */ + krk_push(krk_dict_of(0,NULL,0)); + + /* Run the class function on it */ + krk_push(krk_callStack(1)); + + /* Now make a class */ + KrkClass * _class = krk_newClass(name, base); + krk_push(OBJECT_VAL(_class)); + + /* Now copy the values over */ + krk_tableAddAll(AS_DICT(krk_peek(1)), &_class->methods); + krk_swap(1); + krk_pop(); /* Get rid of the namespace dict */ + + /* Now assign the upvalue for the original function if it's a closure. */ + if (IS_CLOSURE(func)) { + if (AS_CLOSURE(func)->upvalueCount && AS_CLOSURE(func)->upvalues[0]->location == -1 && IS_NONE(AS_CLOSURE(func)->upvalues[0]->closed)) { + AS_CLOSURE(func)->upvalues[0]->closed = krk_peek(0); + } + } + + krk_finalizeClass(_class); + _callSetName(_class); + + /* We're done, return the resulting class object. */ + return krk_pop(); +} + _noexport void _createAndBind_builtins(void) { vm.baseClasses->objectClass = krk_newClass(S("object"), NULL); @@ -1513,5 +1605,8 @@ void _createAndBind_builtins(void) { BUILTIN_FUNCTION("format", FUNC_NAME(krk,format), "@brief Format a value for string printing.\n" "@arguments value[,format_spec]"); + + + BUILTIN_FUNCTION("__build_class__", FUNC_NAME(krk,__build_class__), "fuck"); } diff --git a/src/compiler.c b/src/compiler.c index 9ddb794..9859675 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -100,6 +100,7 @@ typedef enum { EXPR_ASSIGN_TARGET, /**< This expression is definitely an assignment target or chained to one. */ EXPR_DEL_TARGET, /**< This expression is in the target list of a 'del' statement. */ EXPR_METHOD_CALL, /**< This expression is the parameter list of a method call; only used by @ref dot and @ref call */ + EXPR_CLASS_PARAMETERS, } ExpressionType; struct RewindState; @@ -148,6 +149,7 @@ typedef struct { typedef struct { size_t index; /**< Enclosing local index or upvalue index. */ char isLocal; /**< Flag indicating if @ref index is a local or upvalue index. */ + KrkToken name; } Upvalue; /** @@ -391,6 +393,17 @@ static void initCompiler(struct GlobalState * state, Compiler * compiler, Functi state->current->codeobject->potentialPositionals = 1; } + if (type == TYPE_CLASS) { + Local * local = &state->current->locals[state->current->localCount++]; + local->depth = 0; + local->isCaptured = 0; + local->name.start = ""; + local->name.length = 0; + renameLocal(state, 0, local->name); + state->current->codeobject->requiredArgs = 1; + state->current->codeobject->potentialPositionals = 1; + } + if (isCoroutine(type)) state->current->codeobject->obj.flags |= KRK_OBJ_FLAGS_CODEOBJECT_IS_COROUTINE; } @@ -1337,7 +1350,7 @@ static void doUpvalues(struct GlobalState * state, Compiler * compiler, KrkCodeO assert(!!function->upvalueCount == !!compiler->upvalues); for (size_t i = 0; i < function->upvalueCount; ++i) { size_t index = compiler->upvalues[i].index; - emitByte((compiler->upvalues[i].isLocal ? 1 : 0) | ((index > 255) ? 2 : 0)); + emitByte((compiler->upvalues[i].isLocal) | ((index > 255) ? 2 : 0)); if (index > 255) { emitByte((index >> 16) & 0xFF); emitByte((index >> 8) & 0xFF); @@ -1562,15 +1575,14 @@ static void classBody(struct GlobalState * state, size_t blockWidth) { KrkToken name = state->parser.previous; match(TOKEN_COLON); /* Get __annotations__ from class */ - emitBytes(OP_DUP, 0); KrkToken annotations = syntheticToken("__annotations__"); size_t ind = identifierConstant(state, &annotations); if (!state->currentClass->hasAnnotations) { EMIT_OPERAND_OP(OP_MAKE_DICT, 0); - EMIT_OPERAND_OP(OP_SET_PROPERTY, ind); + EMIT_OPERAND_OP(OP_SET_NAME, ind); state->currentClass->hasAnnotations = 1; } else { - EMIT_OPERAND_OP(OP_GET_PROPERTY, ind); + EMIT_OPERAND_OP(OP_GET_NAME, ind); } emitConstant(OBJECT_VAL(krk_copyString(name.start, name.length))); parsePrecedence(state, PREC_TERNARY); @@ -1586,7 +1598,8 @@ static void classBody(struct GlobalState * state, size_t blockWidth) { parsePrecedence(state, PREC_COMMA); rememberClassProperty(state, ind); - EMIT_OPERAND_OP(OP_CLASS_PROPERTY, ind); + EMIT_OPERAND_OP(OP_SET_NAME, ind); + emitByte(OP_POP); if (!match(TOKEN_EOL) && !match(TOKEN_EOF)) { errorAtCurrent("Expected end of line after class attribute declaration"); @@ -1626,7 +1639,8 @@ static void classBody(struct GlobalState * state, size_t blockWidth) { function(state, type, blockWidth); rememberClassProperty(state, ind); - EMIT_OPERAND_OP(OP_CLASS_PROPERTY, ind); + EMIT_OPERAND_OP(OP_SET_NAME, ind); + emitByte(OP_POP); } } @@ -1636,28 +1650,29 @@ static void classBody(struct GlobalState * state, size_t blockWidth) { EMIT_OPERAND_OP(how, val_ind); \ KrkToken name_tok = syntheticToken(propName); \ size_t name_ind = identifierConstant(state, &name_tok); \ - EMIT_OPERAND_OP(OP_CLASS_PROPERTY, name_ind); \ + EMIT_OPERAND_OP(OP_SET_NAME, name_ind); \ + emitByte(OP_POP); \ } while (0) +static size_t addUpvalue(struct GlobalState * state, Compiler * compiler, ssize_t index, int isLocal, KrkToken name); static KrkToken classDeclaration(struct GlobalState * state) { size_t blockWidth = (state->parser.previous.type == TOKEN_INDENTATION) ? state->parser.previous.length : 0; advance(); /* Collect the `class` */ consume(TOKEN_IDENTIFIER, "Expected class name after 'class'."); + + KrkToken buildClass = syntheticToken("__build_class__"); + size_t ind = identifierConstant(state, &buildClass); + EMIT_OPERAND_OP(OP_GET_GLOBAL, ind); + Compiler subcompiler; initCompiler(state, &subcompiler, TYPE_CLASS); subcompiler.codeobject->chunk.filename = subcompiler.enclosing->codeobject->chunk.filename; beginScope(state); - /* We want to expose the mangled name within the class definition, which then - * becomes available as a nonlocal, but we want to hand the non-mangled name - * to the CLASS instruction so that __name__ is right. */ - size_t nameInd = nonidentifierTokenConstant(state, &state->parser.previous); - identifierConstant(state, &state->parser.previous); - declareVariable(state); - EMIT_OPERAND_OP(OP_CLASS, nameInd); - markInitialized(state); + KrkToken classNameToken = state->parser.previous; + assert(addUpvalue(state, state->current, 0, 4, classNameToken) == 0); ClassCompiler classCompiler; classCompiler.name = state->parser.previous; @@ -1665,14 +1680,23 @@ static KrkToken classDeclaration(struct GlobalState * state) { state->currentClass = &classCompiler; classCompiler.hasAnnotations = 0; + RewindState parameters = {recordChunk(currentChunk()), krk_tellScanner(&state->scanner), state->parser}; + + /* Class parameters */ if (match(TOKEN_LEFT_PAREN)) { - startEatingWhitespace(); - if (!check(TOKEN_RIGHT_PAREN)) { - expression(state); - emitByte(OP_INHERIT); + int parenDepth = 0; + while (!check(TOKEN_EOF)) { + if (check(TOKEN_RIGHT_PAREN) && parenDepth == 0) { + advance(); + break; + } else if (match(TOKEN_LEFT_BRACE)) { + parenDepth++; + } else if (match(TOKEN_RIGHT_BRACE)) { + parenDepth--; + } else { + advance(); + } } - stopEatingWhitespace(); - consume(TOKEN_RIGHT_PAREN, "Expected ')' after superclass."); } beginScope(state); @@ -1693,7 +1717,10 @@ static KrkToken classDeclaration(struct GlobalState * state) { advance(); if (match(TOKEN_STRING) || match(TOKEN_BIG_STRING)) { string(state, EXPR_NORMAL); - emitByte(OP_DOCSTRING); + KrkToken doc = syntheticToken("__doc__"); + size_t ind = identifierConstant(state, &doc); + EMIT_OPERAND_OP(OP_SET_NAME, ind); + emitByte(OP_POP); consume(TOKEN_EOL,"Garbage after docstring defintion"); if (!check(TOKEN_INDENTATION) || state->parser.current.length != currentIndentation) { goto _pop_class; @@ -1710,14 +1737,30 @@ static KrkToken classDeclaration(struct GlobalState * state) { } } /* else empty class (and at end of file?) we'll allow it for now... */ _pop_class: - emitByte(OP_FINALIZE); + //emitByte(OP_FINALIZE); state->currentClass = state->currentClass->enclosing; KrkCodeObject * makeclass = endCompiler(state); size_t indFunc = krk_addConstant(currentChunk(), OBJECT_VAL(makeclass)); EMIT_OPERAND_OP(OP_CLOSURE, indFunc); doUpvalues(state, &subcompiler, makeclass); freeCompiler(&subcompiler); - emitBytes(OP_CALL, 0); + + RewindState afterFunction = {recordChunk(currentChunk()), krk_tellScanner(&state->scanner), state->parser}; + + size_t nameInd = nonidentifierTokenConstant(state, &classNameToken); + EMIT_OPERAND_OP(OP_CONSTANT, nameInd); + + krk_rewindScanner(&state->scanner, parameters.oldScanner); + state->parser = parameters.oldParser; + + if (match(TOKEN_LEFT_PAREN)) { + call(state, EXPR_CLASS_PARAMETERS, NULL); + } else { + emitBytes(OP_CALL, 2); + } + + krk_rewindScanner(&state->scanner, afterFunction.oldScanner); + state->parser = afterFunction.oldParser; return classCompiler.name; } @@ -1853,7 +1896,8 @@ static KrkToken decorator(struct GlobalState * state, size_t level, FunctionType } else { size_t ind = identifierConstant(state, &funcName); rememberClassProperty(state, ind); - EMIT_OPERAND_OP(OP_CLASS_PROPERTY, ind); + EMIT_OPERAND_OP(OP_SET_NAME, ind); + emitByte(OP_POP); } } @@ -2896,7 +2940,7 @@ _cleanupError: #undef PUSH_CHAR } -static size_t addUpvalue(struct GlobalState * state, Compiler * compiler, ssize_t index, int isLocal) { +static size_t addUpvalue(struct GlobalState * state, Compiler * compiler, ssize_t index, int isLocal, KrkToken name) { size_t upvalueCount = compiler->codeobject->upvalueCount; for (size_t i = 0; i < upvalueCount; ++i) { Upvalue * upvalue = &compiler->upvalues[i]; @@ -2911,19 +2955,28 @@ static size_t addUpvalue(struct GlobalState * state, Compiler * compiler, ssize_ } compiler->upvalues[upvalueCount].isLocal = isLocal; compiler->upvalues[upvalueCount].index = index; + compiler->upvalues[upvalueCount].name = name; return compiler->codeobject->upvalueCount++; } static ssize_t resolveUpvalue(struct GlobalState * state, Compiler * compiler, KrkToken * name) { + size_t upvalueCount = compiler->codeobject->upvalueCount; + for (size_t i = 0; i < upvalueCount; ++i) { + if (identifiersEqual(name, &compiler->upvalues[i].name)) { + return i; + } + } + if (compiler->enclosing == NULL) return -1; + ssize_t local = resolveLocal(state, compiler->enclosing, name); if (local != -1) { compiler->enclosing->locals[local].isCaptured = 1; - return addUpvalue(state, compiler, local, 1); + return addUpvalue(state, compiler, local, 1, *name); } ssize_t upvalue = resolveUpvalue(state, compiler->enclosing, name); if (upvalue != -1) { - return addUpvalue(state, compiler, upvalue, 0); + return addUpvalue(state, compiler, upvalue, 0, *name); } return -1; } @@ -2959,8 +3012,7 @@ static void namedVariable(struct GlobalState * state, KrkToken name, int exprTyp KrkString * constant = AS_STRING(currentChunk()->constants.values[properties->ind]); if (constant->length == name.length && !memcmp(constant->chars, name.start, name.length)) { ssize_t arg = properties->ind; - EMIT_OPERAND_OP(OP_GET_LOCAL, 0); - DO_VARIABLE(OP_SET_PROPERTY, OP_GET_PROPERTY, OP_NONE); + DO_VARIABLE(OP_SET_NAME, OP_GET_NAME, OP_NONE); return; } properties = properties->next; @@ -3579,6 +3631,8 @@ static void call(struct GlobalState * state, int exprType, RewindState *rewind) if (exprType == EXPR_METHOD_CALL) { EMIT_OPERAND_OP(OP_CALL_METHOD, argCount); + } else if (exprType == EXPR_CLASS_PARAMETERS) { + EMIT_OPERAND_OP(OP_CALL, (argCount + 2)); } else { EMIT_OPERAND_OP(OP_CALL, argCount); } diff --git a/src/kuroko/object.h b/src/kuroko/object.h index e7db518..cca96a9 100644 --- a/src/kuroko/object.h +++ b/src/kuroko/object.h @@ -188,11 +188,11 @@ typedef void (*KrkCleanupCallback)(struct KrkInstance *); */ typedef struct KrkClass { KrkObj obj; /**< @protected @brief Base */ + struct KrkClass * _class; /**< @brief Metaclass */ + KrkTable methods; /**< @brief General attributes table */ KrkString * name; /**< @brief Name of the class */ KrkString * filename; /**< @brief Filename of the original source that defined the codeobject for the class */ - KrkString * docstring; /**< @brief Storage for the class's docstring */ struct KrkClass * base; /**< @brief Pointer to base class implementation */ - KrkTable methods; /**< @brief General attributes table */ size_t allocSize; /**< @brief Size to allocate when creating instances of this class */ KrkCleanupCallback _ongcscan; /**< @brief C function to call when the garbage collector visits an instance of this class in the scan phase */ KrkCleanupCallback _ongcsweep; /**< @brief C function to call when the garbage collector is discarding an instance of this class */ diff --git a/src/kuroko/util.h b/src/kuroko/util.h index e84d740..9c6e638 100644 --- a/src/kuroko/util.h +++ b/src/kuroko/util.h @@ -264,7 +264,7 @@ extern KrkValue FUNC_NAME(str,format)(int,const KrkValue*,int); #define krk_string_format FUNC_NAME(str,format) static inline void _setDoc_class(KrkClass * thing, const char * text, size_t size) { - thing->docstring = krk_copyString(text, size); + krk_attachNamedObject(&thing->methods, "__doc__", (KrkObj*)krk_copyString(text, size)); } static inline void _setDoc_instance(KrkInstance * thing, const char * text, size_t size) { krk_attachNamedObject(&thing->fields, "__doc__", (KrkObj*)krk_copyString(text, size)); diff --git a/src/memory.c b/src/memory.c index 649b3cc..50b6bac 100644 --- a/src/memory.c +++ b/src/memory.c @@ -371,7 +371,6 @@ static void blackenObject(KrkObj * object) { KrkClass * _class = (KrkClass *)object; krk_markObject((KrkObj*)_class->name); krk_markObject((KrkObj*)_class->filename); - krk_markObject((KrkObj*)_class->docstring); krk_markObject((KrkObj*)_class->base); krk_markTable(&_class->methods); break; diff --git a/src/obj_base.c b/src/obj_base.c index 3356e63..76756c2 100644 --- a/src/obj_base.c +++ b/src/obj_base.c @@ -43,14 +43,6 @@ KRK_Method(type,__file__) { return self->filename ? OBJECT_VAL(self->filename) : NONE_VAL(); } -KRK_Method(type,__doc__) { - if (argc > 1) { - if (!IS_STRING(argv[1])) return TYPE_ERROR(str,argv[1]); - self->docstring = AS_STRING(argv[1]); - } - return self->docstring ? OBJECT_VAL(self->docstring) : NONE_VAL(); -} - KRK_Method(type,__str__) { /* Determine if this class has a module */ KrkValue module = NONE_VAL(); @@ -140,12 +132,11 @@ KRK_Method(type,__call__) { _noexport void _createAndBind_type(void) { KrkClass * type = ADD_BASE_CLASS(vm.baseClasses->typeClass, "type", vm.baseClasses->objectClass); - type->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT; + //type->obj.flags |= KRK_OBJ_FLAGS_NO_INHERIT; type->allocSize = sizeof(KrkClass); BIND_PROP(type,__base__); BIND_PROP(type,__file__); - BIND_PROP(type,__doc__); BIND_PROP(type,__name__); BIND_METHOD(type,__init__); diff --git a/src/opcodes.h b/src/opcodes.h index d411bee..6003d47 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -75,10 +75,10 @@ SIMPLE(OP_NOT) OPERAND(OP_CALL, NOOP) JUMP(OP_PUSH_WITH,+) SIMPLE(OP_GREATER_EQUAL) -CONSTANT(OP_CLASS_PROPERTY, NOOP) +CONSTANT(OP_SET_NAME, NOOP) SIMPLE(OP_INPLACE_ADD) CONSTANT(OP_GET_METHOD, NOOP) -CONSTANT(OP_CLASS,NOOP) +OPERAND(OP_CLASS,NOOP) SIMPLE(OP_LESS_EQUAL) SIMPLE(OP_DOCSTRING) SIMPLE(OP_MATMUL) @@ -113,3 +113,4 @@ JUMP(OP_CALL_ITER,+) JUMP(OP_JUMP_IF_TRUE_OR_POP,+) SIMPLE(OP_TRY_ELSE) OPERAND(OP_MISSING_KW, NOOP) +CONSTANT(OP_GET_NAME, NOOP) diff --git a/src/vm.c b/src/vm.c index da42774..8dba30d 100644 --- a/src/vm.c +++ b/src/vm.c @@ -268,50 +268,6 @@ void krk_finalizeClass(KrkClass * _class) { } } -/** - * This should really be the default behavior of type.__new__? - */ -static void _callSetName(KrkClass * _class) { - KrkValue setnames = krk_list_of(0,NULL,0); - krk_push(setnames); - extern FUNC_SIG(list,append); - - /* The semantics of this require that we first collect all of the relevant items... */ - for (size_t i = 0; i < _class->methods.capacity; ++i) { - KrkTableEntry * entry = &_class->methods.entries[i]; - if (!IS_KWARGS(entry->key)) { - KrkClass * type = krk_getType(entry->value); - if (type->_set_name) { - FUNC_NAME(list,append)(2,(KrkValue[]){setnames,entry->key},0); - FUNC_NAME(list,append)(2,(KrkValue[]){setnames,entry->value},0); - } - } - } - - /* Then call __set_name__ on them */ - for (size_t i = 0; i < AS_LIST(setnames)->count; i += 2) { - KrkValue name = AS_LIST(setnames)->values[i]; - KrkValue value = AS_LIST(setnames)->values[i+1]; - KrkClass * type = krk_getType(value); - if (type->_set_name) { - krk_push(value); - krk_push(OBJECT_VAL(_class)); - krk_push(name); - krk_callDirect(type->_set_name, 3); - - /* If any of these raises an exception, bail; CPython raises - * an outer exception, setting the cause, but I'm being lazy - * at the moment... */ - if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) { - break; - } - } - } - - /* List used to store name+value pairs */ - krk_pop(); -} - /** * Maps values to their base classes. * Internal version of type(). @@ -342,6 +298,7 @@ inline KrkClass * krk_getType(KrkValue of) { return vm.baseClasses->notImplClass; case KRK_VAL_OBJECT: if (IS_INSTANCE(of)) return AS_INSTANCE(of)->_class; + if (IS_CLASS(of) && AS_CLASS(of)->_class) return AS_CLASS(of)->_class; return *(KrkClass **)((char*)vm.baseClasses + objClasses[AS_OBJECT(of)->type]); default: if (IS_FLOATING(of)) return vm.baseClasses->floatClass; @@ -2280,12 +2237,8 @@ _finishReturn: (void)0; break; } case OP_FINALIZE: { - KrkClass * _class = AS_CLASS(krk_peek(0)); - /* Store special methods for quick access */ - krk_finalizeClass(_class); - /* Call __set_name__? */ - _callSetName(_class); - break; + krk_runtimeError(vm.exceptions->typeError, "OP_FINALIZE called"); + goto _finishException; } case OP_INHERIT: { KrkValue superclass = krk_peek(0); @@ -2311,9 +2264,8 @@ _finishReturn: (void)0; break; } case OP_DOCSTRING: { - KrkClass * me = AS_CLASS(krk_peek(1)); - me->docstring = AS_STRING(krk_pop()); - break; + krk_runtimeError(vm.exceptions->typeError, "OP_DOCSTRING called"); + goto _finishException; } case OP_SWAP: krk_swap(1); @@ -2657,6 +2609,10 @@ _finishReturn: (void)0; } if (isLocal & 1) { closure->upvalues[i] = captureUpvalue(frame->slots + index); + } else if (isLocal & 4) { + closure->upvalues[i] = krk_newUpvalue(0); + closure->upvalues[i]->closed = NONE_VAL(); + closure->upvalues[i]->location = -1; } else { closure->upvalues[i] = frame->closure->upvalues[index]; } @@ -2681,12 +2637,11 @@ _finishReturn: (void)0; THREE_BYTE_OPERAND; case OP_CLASS: { ONE_BYTE_OPERAND; - KrkString * name = READ_STRING(OPERAND); - KrkClass * _class = krk_newClass(name, vm.baseClasses->objectClass); - krk_push(OBJECT_VAL(_class)); - _class->filename = frame->closure->function->chunk.filename; - krk_attachNamedObject(&_class->methods, "__func__", (KrkObj*)frame->closure); - break; + /* OPERAND is number of arguments to pass to initializer */ + /* stackTop[-OPERAND-1] is class function */ + /* stackTop[-OPERAND-2] is class name */ + krk_runtimeError(vm.exceptions->typeError, "what the fuck"); + goto _finishException; } case OP_IMPORT_FROM_LONG: THREE_BYTE_OPERAND; @@ -2746,10 +2701,16 @@ _finishReturn: (void)0; } break; } - case OP_CLASS_PROPERTY_LONG: + case OP_SET_NAME_LONG: THREE_BYTE_OPERAND; - case OP_CLASS_PROPERTY: { + case OP_SET_NAME: { ONE_BYTE_OPERAND; + krk_push(krk_currentThread.stack[frame->slots]); + krk_swap(1); + krk_push(OBJECT_VAL(READ_STRING(OPERAND))); + krk_swap(1); + commonMethodInvoke(offsetof(KrkClass,_setter), 3, "'%T' object doesn't support item assignment"); + #if 0 KrkValue method = krk_peek(0); KrkClass * _class = AS_CLASS(krk_peek(1)); KrkValue name = OBJECT_VAL(READ_STRING(OPERAND)); @@ -2761,6 +2722,16 @@ _finishReturn: (void)0; AS_CLOSURE(method)->obj.flags |= KRK_OBJ_FLAGS_FUNCTION_IS_STATIC_METHOD; } krk_pop(); + #endif + break; + } + case OP_GET_NAME_LONG: + THREE_BYTE_OPERAND; + case OP_GET_NAME: { + ONE_BYTE_OPERAND; + krk_push(krk_currentThread.stack[frame->slots]); + krk_push(OBJECT_VAL(READ_STRING(OPERAND))); + commonMethodInvoke(offsetof(KrkClass,_getter), 2, "'%T' object doesn't support item assignment"); break; } case OP_GET_SUPER_LONG: diff --git a/test/testAnnotations.krk.expect b/test/testAnnotations.krk.expect index d84f0fc..89f6449 100644 --- a/test/testAnnotations.krk.expect +++ b/test/testAnnotations.krk.expect @@ -1,7 +1,7 @@ I am a function. [42] {'return': , 'a': , 'b': } -{'return': None, 'anint': , 'self': , 'adict': 'dict[str,object]'} +{'return': None, 'anint': , 'self': None, 'adict': 'dict[str,object]'} I am a method taking a dict. None {'astr': , 'abool': } diff --git a/test/testAttributePacking.krk.expect b/test/testAttributePacking.krk.expect index 45c5625..10fa811 100644 --- a/test/testAttributePacking.krk.expect +++ b/test/testAttributePacking.krk.expect @@ -1,4 +1,4 @@ -['__class__', '__dir__', '__eq__', '__format__', '__hash__', '__init__', '__new__', '__repr__', '__setattr__', '__str__', 'longList', 'ofAttributes', 'onThatObject', 'thatWeWantToSet'] +['__class__', '__dir__', '__doc__', '__eq__', '__format__', '__hash__', '__init__', '__new__', '__repr__', '__setattr__', '__str__', 'longList', 'ofAttributes', 'onThatObject', 'thatWeWantToSet'] 1 2 3 diff --git a/test/testDel.krk.expect b/test/testDel.krk.expect index 639d3b4..897ad4a 100644 --- a/test/testDel.krk.expect +++ b/test/testDel.krk.expect @@ -7,10 +7,10 @@ False [1, 3, 4, 5] [1, 3, 4] list index out of range: 3 -['__class__', '__dir__', '__eq__', '__format__', '__hash__', '__init__', '__new__', '__repr__', '__setattr__', '__str__', 'baz', 'qux'] +['__class__', '__dir__', '__doc__', '__eq__', '__format__', '__hash__', '__init__', '__new__', '__repr__', '__setattr__', '__str__', 'baz', 'qux'] 42 -['__class__', '__dir__', '__eq__', '__format__', '__hash__', '__init__', '__new__', '__repr__', '__setattr__', '__str__', 'qux'] +['__class__', '__dir__', '__doc__', '__eq__', '__format__', '__hash__', '__init__', '__new__', '__repr__', '__setattr__', '__str__', 'qux'] hi 'object' object has no attribute 'baz' -['__class__', '__dir__', '__eq__', '__format__', '__hash__', '__init__', '__new__', '__repr__', '__setattr__', '__str__'] +['__class__', '__dir__', '__doc__', '__eq__', '__format__', '__hash__', '__init__', '__new__', '__repr__', '__setattr__', '__str__'] 'object' object has no attribute 'bar' diff --git a/test/testGetattrDir.krk.expect b/test/testGetattrDir.krk.expect index 23fbbf6..3e1e0c9 100644 --- a/test/testGetattrDir.krk.expect +++ b/test/testGetattrDir.krk.expect @@ -1,3 +1,3 @@ -['__class__', '__dir__', '__eq__', '__format__', '__func__', '__getattr__', '__hash__', '__init__', '__module__', '__new__', '__qualname__', '__repr__', '__setattr__', '__str__', '_dict'] +['__class__', '__dir__', '__doc__', '__eq__', '__format__', '__getattr__', '__hash__', '__init__', '__module__', '__new__', '__qualname__', '__repr__', '__setattr__', '__str__', '_dict'] 1 -['__class__', '__dir__', '__eq__', '__format__', '__func__', '__hash__', '__init__', '__module__', '__new__', '__qualname__', '__repr__', '__setattr__', '__str__', 'butts'] +['__class__', '__dir__', '__doc__', '__eq__', '__format__', '__hash__', '__init__', '__module__', '__new__', '__qualname__', '__repr__', '__setattr__', '__str__', 'butts']