Very initial rebuild of class creation
This commit is contained in:
parent
f9df8b22ef
commit
617d30d804
@ -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");
|
||||
}
|
||||
|
||||
|
114
src/compiler.c
114
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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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__);
|
||||
|
@ -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)
|
||||
|
93
src/vm.c
93
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:
|
||||
|
@ -1,7 +1,7 @@
|
||||
I am a function.
|
||||
[42]
|
||||
{'return': <class 'list'>, 'a': <class 'int'>, 'b': <class 'float'>}
|
||||
{'return': None, 'anint': <class 'int'>, 'self': <class '__main__.Foo'>, 'adict': 'dict[str,object]'}
|
||||
{'return': None, 'anint': <class 'int'>, 'self': None, 'adict': 'dict[str,object]'}
|
||||
I am a method taking a dict.
|
||||
None
|
||||
{'astr': <class 'str'>, 'abool': <class 'bool'>}
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
|
@ -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']
|
||||
|
Loading…
Reference in New Issue
Block a user