Fix up function, object repring and add __qualname__ to functions

This commit is contained in:
K Lange 2021-03-11 19:05:21 +09:00
parent 1201dc8115
commit f655ca7f61
21 changed files with 294 additions and 215 deletions

View File

@ -658,13 +658,26 @@ static KrkValue obj_hash(int argc, KrkValue argv[], int hasKw) {
*/
static KrkValue _strBase(int argc, KrkValue argv[], int hasKw) {
KrkClass * type = krk_getType(argv[0]);
size_t allocSize = sizeof("<instance of . at 0x1234567812345678>") + type->name->length;
KrkValue module = NONE_VAL();
krk_tableGet(&type->methods, OBJECT_VAL(S("__module__")), &module);
KrkValue qualname = NONE_VAL();
krk_tableGet(&type->methods, OBJECT_VAL(S("__qualname__")), &qualname);
KrkString * name = IS_STRING(qualname) ? AS_STRING(qualname) : type->name;
int includeModule = !(IS_NONE(module) || (IS_STRING(module) && AS_STRING(module) == S("__builtins__")));
size_t allocSize = sizeof("<. object at 0x1234567812345678>") + name->length;
if (includeModule) allocSize += AS_STRING(module)->length + 1;
char * tmp = malloc(allocSize);
size_t len;
if (IS_OBJECT(argv[0])) {
len = snprintf(tmp, allocSize, "<instance of %s at %p>", type->name->chars, (void*)AS_OBJECT(argv[0]));
len = snprintf(tmp, allocSize, "<%s%s%s object at %p>",
includeModule ? AS_CSTRING(module) : "",
includeModule ? "." : "",
name->chars,
(void*)AS_OBJECT(argv[0]));
} else {
len = snprintf(tmp, allocSize, "<instance of %s>", type->name->chars);
len = snprintf(tmp, allocSize, "<%s object>", name->chars);
}
KrkValue out = OBJECT_VAL(krk_copyString(tmp, len));
free(tmp);

View File

@ -153,6 +153,34 @@ static int isMethod(int type) {
return type == TYPE_METHOD || type == TYPE_INIT || type == TYPE_PROPERTY;
}
static char * calculateQualName(void) {
static char space[1024]; /* We'll just truncate if we need to */
space[1023] = '\0';
char * writer = &space[1023];
#define WRITE(s) do { \
size_t len = strlen(s); \
if (writer - len < space) break; \
writer -= len; \
memcpy(writer, s, len); \
} while (0)
WRITE(current->function->name->chars);
/* Go up by _compiler_, ignore class compilers as we don't need them. */
Compiler * ptr = current->enclosing;
while (ptr->enclosing) { /* Ignores the top level module */
if (ptr->type != TYPE_CLASS) {
/* We must be the locals of a function. */
WRITE("<locals>.");
}
WRITE(".");
WRITE(ptr->function->name->chars);
ptr = ptr->enclosing;
}
return writer;
}
static void initCompiler(Compiler * compiler, FunctionType type) {
compiler->enclosing = current;
current = compiler;
@ -178,6 +206,8 @@ static void initCompiler(Compiler * compiler, FunctionType type) {
if (type != TYPE_MODULE) {
current->function->name = krk_copyString(parser.previous.start, parser.previous.length);
char * qualname = calculateQualName();
current->function->qualname = krk_copyString(qualname, strlen(qualname));
}
if (isMethod(type)) {
@ -1049,34 +1079,6 @@ static void method(size_t blockWidth) {
emitByte(OP_POP); \
} while (0)
static char * calculateQualName(void) {
static char space[1024]; /* We'll just truncate if we need to */
space[1023] = '\0';
char * writer = &space[1023];
#define WRITE(s) do { \
size_t len = strlen(s); \
if (writer - len < space) break; \
writer -= len; \
memcpy(writer, s, len); \
} while (0)
WRITE(current->function->name->chars);
/* Go up by _compiler_, ignore class compilers as we don't need them. */
Compiler * ptr = current->enclosing;
while (ptr->enclosing) { /* Ignores the top level module */
if (ptr->type != TYPE_CLASS) {
/* We must be the locals of a function. */
WRITE("<locals>.");
}
WRITE(".");
WRITE(ptr->function->name->chars);
ptr = ptr->enclosing;
}
return writer;
}
static KrkToken classDeclaration() {
size_t blockWidth = (parser.previous.type == TOKEN_INDENTATION) ? parser.previous.length : 0;
advance(); /* Collect the `class` */

View File

@ -5,23 +5,6 @@
#include "util.h"
#include "debug.h"
/* function.__doc__ */
static KrkValue _closure_get_doc(int argc, KrkValue argv[], int hasKw) {
if (IS_NATIVE(argv[0]) && AS_NATIVE(argv[0])->doc) {
return OBJECT_VAL(krk_copyString(AS_NATIVE(argv[0])->doc, strlen(AS_NATIVE(argv[0])->doc)));
} else if (IS_CLOSURE(argv[0]) && AS_CLOSURE(argv[0])->function->docstring) {
return OBJECT_VAL(AS_CLOSURE(argv[0])->function->docstring);
} else {
return NONE_VAL();
}
}
/* method.__doc__ */
static KrkValue _bound_get_doc(int argc, KrkValue argv[], int hasKw) {
KrkBoundMethod * boundMethod = AS_BOUND_METHOD(argv[0]);
return _closure_get_doc(1, (KrkValue[]){OBJECT_VAL(boundMethod->method)}, 0);
}
/* Check for and return the name of a native function as a string object */
static KrkValue nativeFunctionName(KrkValue func) {
const char * string = ((KrkNative*)AS_OBJECT(func))->name;
@ -30,44 +13,143 @@ static KrkValue nativeFunctionName(KrkValue func) {
return OBJECT_VAL(krk_copyString(string,len));
}
static KrkValue _function_get_name(int argc, KrkValue argv[], int hasKw) {
return AS_FUNCTION(argv[0])->name ? OBJECT_VAL(AS_FUNCTION(argv[0])->name) : OBJECT_VAL(S(""));
}
#define IS_codeobject(o) IS_FUNCTION(o)
#define IS_method(o) IS_BOUND_METHOD(o)
#define IS_function(o) (IS_CLOSURE(o)|IS_NATIVE(o))
/* function.__name__ */
static KrkValue _closure_get_name(int argc, KrkValue argv[], int hasKw) {
if (IS_NATIVE(argv[0])) return nativeFunctionName(argv[0]);
else if (!IS_CLOSURE(argv[0])) return krk_runtimeError(vm.exceptions->typeError, "'%s' is neither a closure nor a native", krk_typeName(argv[0]));
return AS_CLOSURE(argv[0])->function->name ? OBJECT_VAL(AS_CLOSURE(argv[0])->function->name) : OBJECT_VAL(S(""));
}
#define AS_codeobject(o) AS_FUNCTION(o)
#define AS_method(o) AS_BOUND_METHOD(o)
#define AS_function(o) (o)
/* method.__name__ */
static KrkValue _bound_get_name(int argc, KrkValue argv[], int hasKw) {
KrkBoundMethod * boundMethod = AS_BOUND_METHOD(argv[0]);
return _closure_get_name(1, (KrkValue[]){OBJECT_VAL(boundMethod->method)}, hasKw);
}
#define CURRENT_NAME self
#define CURRENT_CTYPE KrkValue
static KrkValue _function_ip_to_line(int argc, KrkValue argv[], int hasKw) {
if (argc < 2) return krk_runtimeError(vm.exceptions->argumentError, "%s() expects exactly 2 arguments", "ip_to_line");
if (!IS_FUNCTION(argv[0])) return NONE_VAL();
if (!IS_INTEGER(argv[1])) return TYPE_ERROR(int,argv[1]);
return INTEGER_VAL(krk_lineNumber(&AS_FUNCTION(argv[0])->chunk, AS_INTEGER(argv[1])));
}
KRK_METHOD(function,__doc__,{
METHOD_TAKES_NONE();
static KrkValue _closure_ip_to_line(int argc, KrkValue argv[], int hasKw) {
if (argc < 2) return krk_runtimeError(vm.exceptions->argumentError, "%s() expects exactly 2 arguments", "ip_to_line");
if (!IS_CLOSURE(argv[0])) return NONE_VAL();
if (!IS_INTEGER(argv[1])) return TYPE_ERROR(int,argv[1]);
return INTEGER_VAL(krk_lineNumber(&AS_CLOSURE(argv[0])->function->chunk, AS_INTEGER(argv[1])));
}
if (IS_NATIVE(self) && AS_NATIVE(self)->doc) {
return OBJECT_VAL(krk_copyString(AS_NATIVE(self)->doc, strlen(AS_NATIVE(self)->doc)));
} else if (IS_CLOSURE(self) && AS_CLOSURE(self)->function->docstring) {
return OBJECT_VAL(AS_CLOSURE(self)->function->docstring);
}
})
static KrkValue _bound_ip_to_line(int argc, KrkValue argv[], int hasKw) {
KrkBoundMethod * boundMethod = AS_BOUND_METHOD(argv[0]);
return _closure_ip_to_line(1, (KrkValue[]){OBJECT_VAL(boundMethod->method)}, hasKw);
}
KRK_METHOD(function,__name__,{
METHOD_TAKES_NONE();
static KrkValue _function_str(int argc, KrkValue argv[], int hasKw) {
KrkValue s = _function_get_name(argc, argv, hasKw);
if (IS_NATIVE(self)) {
return nativeFunctionName(self);
} else if (IS_CLOSURE(self) && AS_CLOSURE(self)->function->name) {
return OBJECT_VAL(AS_CLOSURE(self)->function->name);
}
return OBJECT_VAL(S(""));
})
KRK_METHOD(function,__qualname__,{
METHOD_TAKES_NONE();
if (IS_CLOSURE(self) && AS_CLOSURE(self)->function->qualname) {
return OBJECT_VAL(AS_CLOSURE(self)->function->qualname);
}
})
KRK_METHOD(function,_ip_to_line,{
METHOD_TAKES_EXACTLY(1);
CHECK_ARG(1,int,krk_integer_type,ip);
if (!IS_CLOSURE(self)) return NONE_VAL();
size_t line = krk_lineNumber(&AS_CLOSURE(self)->function->chunk, ip);
return INTEGER_VAL(line);
})
KRK_METHOD(function,__str__,{
METHOD_TAKES_NONE();
struct StringBuilder sb = {0};
pushStringBuilderStr(&sb, "<function ", 10);
/* Do we have a qualified name? */
KrkValue name = FUNC_NAME(function,__qualname__)(1,&self,0);
if (IS_NONE(name)) {
name = FUNC_NAME(function,__name__)(1,&self,0);
}
if (!IS_STRING(name)) name = OBJECT_VAL(S("<unknown>"));
pushStringBuilderStr(&sb, AS_CSTRING(name), AS_STRING(name)->length);
pushStringBuilderStr(&sb," at ", 4);
char address[100];
size_t len = snprintf(address, 100, "%p", (void*)AS_OBJECT(self));
pushStringBuilderStr(&sb, address, len);
pushStringBuilder(&sb,'>');
return finishStringBuilder(&sb);
})
KRK_METHOD(function,__file__,{
METHOD_TAKES_NONE();
if (IS_NATIVE(self)) return OBJECT_VAL(S("<builtin>"));
return AS_CLOSURE(self)->function->chunk.filename ?
OBJECT_VAL(AS_CLOSURE(self)->function->chunk.filename) :
OBJECT_VAL(S(""));
})
KRK_METHOD(function,__args__,{
if (!IS_CLOSURE(self)) return OBJECT_VAL(krk_newTuple(0));
KrkFunction * _self = AS_CLOSURE(self)->function;
KrkTuple * tuple = krk_newTuple(_self->requiredArgs + _self->keywordArgs + _self->collectsArguments + _self->collectsKeywords);
krk_push(OBJECT_VAL(tuple));
for (short i = 0; i < _self->requiredArgs; ++i) {
tuple->values.values[tuple->values.count++] = _self->requiredArgNames.values[i];
}
for (short i = 0; i < _self->keywordArgs; ++i) {
struct StringBuilder sb = {0};
pushStringBuilderStr(&sb, AS_CSTRING(_self->keywordArgNames.values[i]), AS_STRING(_self->keywordArgNames.values[i])->length);
pushStringBuilder(&sb,'=');
tuple->values.values[tuple->values.count++] = finishStringBuilder(&sb);
}
if (_self->collectsArguments) {
struct StringBuilder sb = {0};
pushStringBuilder(&sb, '*');
pushStringBuilderStr(&sb, AS_CSTRING(_self->requiredArgNames.values[_self->requiredArgs]), AS_STRING(_self->requiredArgNames.values[_self->requiredArgs])->length);
tuple->values.values[tuple->values.count++] = finishStringBuilder(&sb);
}
if (_self->collectsKeywords) {
struct StringBuilder sb = {0};
pushStringBuilder(&sb, '*');
pushStringBuilder(&sb, '*');
pushStringBuilderStr(&sb, AS_CSTRING(_self->keywordArgNames.values[_self->keywordArgs]), AS_STRING(_self->keywordArgNames.values[_self->keywordArgs])->length);
tuple->values.values[tuple->values.count++] = finishStringBuilder(&sb);
}
krk_tupleUpdateHash(tuple);
krk_pop();
return OBJECT_VAL(tuple);
})
#undef CURRENT_CTYPE
#define CURRENT_CTYPE KrkFunction*
KRK_METHOD(codeobject,__name__,{
METHOD_TAKES_NONE();
return self->name ? OBJECT_VAL(self->name) : OBJECT_VAL(S(""));
})
KRK_METHOD(codeobject,__str__,{
METHOD_TAKES_NONE();
KrkValue s = FUNC_NAME(codeobject,__name__)(1,argv,0);
if (!IS_STRING(s)) return NONE_VAL();
krk_push(s);
@ -76,140 +158,127 @@ static KrkValue _function_str(int argc, KrkValue argv[], int hasKw) {
snprintf(tmp, len, "<codeobject %s>", AS_CSTRING(s));
s = OBJECT_VAL(krk_copyString(tmp,len-1));
free(tmp);
krk_pop();
return s;
}
})
/* function.__str__ / function.__repr__ */
static KrkValue _closure_str(int argc, KrkValue argv[], int hasKw) {
KrkValue s = _closure_get_name(argc, argv, hasKw);
KRK_METHOD(codeobject,_ip_to_line,{
METHOD_TAKES_EXACTLY(1);
CHECK_ARG(1,int,krk_integer_type,ip);
size_t line = krk_lineNumber(&self->chunk, ip);
return INTEGER_VAL(line);
})
#undef CURRENT_CTYPE
#define CURRENT_CTYPE KrkBoundMethod*
KRK_METHOD(method,__name__,{
METHOD_TAKES_NONE();
return FUNC_NAME(function,__name__)(1,(KrkValue[]){OBJECT_VAL(self->method)},0);
})
KRK_METHOD(method,__qualname__,{
METHOD_TAKES_NONE();
return FUNC_NAME(function,__qualname__)(1,(KrkValue[]){OBJECT_VAL(self->method)},0);
})
KRK_METHOD(method,_ip_to_line,{
METHOD_TAKES_EXACTLY(1);
return FUNC_NAME(function,_ip_to_line)(2,(KrkValue[]){OBJECT_VAL(self->method),argv[1]},0);
})
KRK_METHOD(method,__str__,{
METHOD_TAKES_NONE();
KrkValue s = FUNC_NAME(method,__qualname__)(1,argv,0);
if (!IS_STRING(s)) s = FUNC_NAME(method,__name__)(1,argv,0);
if (!IS_STRING(s)) return NONE_VAL();
krk_push(s);
size_t len = AS_STRING(s)->length + sizeof("<function >");
KrkClass * type = krk_getType(self->receiver);
krk_push(self->receiver);
KrkValue reprVal = krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0);
size_t len = AS_STRING(s)->length + AS_STRING(reprVal)->length + sizeof("<bound method of >") + 1;
char * tmp = malloc(len);
snprintf(tmp, len, "<function %s>", AS_CSTRING(s));
snprintf(tmp, len, "<bound method %s of %s>", AS_CSTRING(s), AS_CSTRING(reprVal));
s = OBJECT_VAL(krk_copyString(tmp,len-1));
free(tmp);
krk_pop();
return s;
}
})
/* method.__str__ / method.__repr__ */
static KrkValue _bound_str(int argc, KrkValue argv[], int hasKw) {
KrkValue s = _bound_get_name(argc, argv, hasKw);
if (!IS_STRING(s)) return NONE_VAL();
krk_push(s);
KRK_METHOD(method,__file__,{
METHOD_TAKES_NONE();
return FUNC_NAME(function,__file__)(1,(KrkValue[]){OBJECT_VAL(self->method)},0);
})
const char * typeName = krk_typeName(AS_BOUND_METHOD(argv[0])->receiver);
size_t len = AS_STRING(s)->length + sizeof("<bound method >") + strlen(typeName) + 1;
char * tmp = malloc(len);
snprintf(tmp, len, "<bound method %s.%s>", typeName, AS_CSTRING(s));
s = OBJECT_VAL(krk_copyString(tmp,len-1));
free(tmp);
krk_pop();
return s;
}
/* function.__file__ */
static KrkValue _closure_get_file(int argc, KrkValue argv[], int hasKw) {
if (!IS_CLOSURE(argv[0])) return OBJECT_VAL(S("<builtin>"));
return AS_CLOSURE(argv[0])->function->chunk.filename ? OBJECT_VAL(AS_CLOSURE(argv[0])->function->chunk.filename) : OBJECT_VAL(S(""));
}
/* method.__file__ */
static KrkValue _bound_get_file(int argc, KrkValue argv[], int hasKw) {
KrkBoundMethod * boundMethod = AS_BOUND_METHOD(argv[0]);
return _closure_get_file(1, (KrkValue[]){OBJECT_VAL(boundMethod->method)}, 0);
}
/* function.__args__ */
static KrkValue _closure_get_argnames(int argc, KrkValue argv[], int hasKw) {
if (!IS_CLOSURE(argv[0])) return OBJECT_VAL(krk_newTuple(0));
KrkFunction * self = AS_CLOSURE(argv[0])->function;
KrkTuple * tuple = krk_newTuple(self->requiredArgs + self->keywordArgs + self->collectsArguments + self->collectsKeywords);
krk_push(OBJECT_VAL(tuple));
for (short i = 0; i < self->requiredArgs; ++i) {
tuple->values.values[tuple->values.count++] = self->requiredArgNames.values[i];
}
for (short i = 0; i < self->keywordArgs; ++i) {
struct StringBuilder sb = {0};
pushStringBuilderStr(&sb, AS_CSTRING(self->keywordArgNames.values[i]), AS_STRING(self->keywordArgNames.values[i])->length);
pushStringBuilder(&sb,'=');
tuple->values.values[tuple->values.count++] = finishStringBuilder(&sb);
}
if (self->collectsArguments) {
struct StringBuilder sb = {0};
pushStringBuilder(&sb, '*');
pushStringBuilderStr(&sb, AS_CSTRING(self->requiredArgNames.values[self->requiredArgs]), AS_STRING(self->requiredArgNames.values[self->requiredArgs])->length);
tuple->values.values[tuple->values.count++] = finishStringBuilder(&sb);
}
if (self->collectsKeywords) {
struct StringBuilder sb = {0};
pushStringBuilder(&sb, '*');
pushStringBuilder(&sb, '*');
pushStringBuilderStr(&sb, AS_CSTRING(self->keywordArgNames.values[self->keywordArgs]), AS_STRING(self->keywordArgNames.values[self->keywordArgs])->length);
tuple->values.values[tuple->values.count++] = finishStringBuilder(&sb);
}
krk_tupleUpdateHash(tuple);
krk_pop();
return OBJECT_VAL(tuple);
}
static KrkValue _bound_get_argnames(int argc, KrkValue argv[], int hasKw) {
KrkBoundMethod * boundMethod = AS_BOUND_METHOD(argv[0]);
return _closure_get_argnames(1, (KrkValue[]){OBJECT_VAL(boundMethod->method)}, 0);
}
KRK_METHOD(method,__args__,{
METHOD_TAKES_NONE();
return FUNC_NAME(function,__args__)(1,(KrkValue[]){OBJECT_VAL(self->method)},0);
})
KRK_METHOD(method,__doc__,{
METHOD_TAKES_NONE();
return FUNC_NAME(function,__doc__)(1,(KrkValue[]){OBJECT_VAL(self->method)},0);
})
KRK_FUNC(staticmethod,{
FUNCTION_TAKES_EXACTLY(1);
CHECK_ARG(0,CLOSURE,KrkClosure*,method);
method->function->isStaticMethod = 1;
return argv[0];
/* Make a copy */
krk_push(OBJECT_VAL(krk_newClosure(method->function)));
/* Copy upvalues */
for (size_t i = 0; i < method->upvalueCount; ++i) {
AS_CLOSURE(krk_peek(0))->upvalues[i] = method->upvalues[i];
}
AS_CLOSURE(krk_peek(0))->isStaticMethod = 1;
return krk_pop();
})
KRK_FUNC(classmethod,{
FUNCTION_TAKES_EXACTLY(1);
CHECK_ARG(0,CLOSURE,KrkClosure*,method);
method->function->isClassMethod = 1;
return argv[0];
/* Make a copy */
krk_push(OBJECT_VAL(krk_newClosure(method->function)));
/* Copy upvalues */
for (size_t i = 0; i < method->upvalueCount; ++i) {
AS_CLOSURE(krk_peek(0))->upvalues[i] = method->upvalues[i];
}
AS_CLOSURE(krk_peek(0))->isClassMethod = 1;
return krk_pop();
})
_noexport
void _createAndBind_functionClass(void) {
ADD_BASE_CLASS(vm.baseClasses->codeobjectClass, "codeobject", vm.baseClasses->objectClass);
krk_defineNative(&vm.baseClasses->codeobjectClass->methods, ".__str__", _function_str);
krk_defineNative(&vm.baseClasses->codeobjectClass->methods, ".__repr__", _function_str);
krk_defineNative(&vm.baseClasses->codeobjectClass->methods, ":__name__", _function_get_name);
krk_defineNative(&vm.baseClasses->codeobjectClass->methods, "_ip_to_line", _function_ip_to_line);
krk_finalizeClass(vm.baseClasses->codeobjectClass);
KrkClass * codeobject = ADD_BASE_CLASS(vm.baseClasses->codeobjectClass, "codeobject", vm.baseClasses->objectClass);
BIND_METHOD(codeobject,__str__);
BIND_METHOD(codeobject,_ip_to_line);
BIND_PROP(codeobject,__name__);
krk_defineNative(&codeobject->methods, ".__repr__", FUNC_NAME(codeobject,__str__));
krk_finalizeClass(codeobject);
ADD_BASE_CLASS(vm.baseClasses->functionClass, "function", vm.baseClasses->objectClass);
krk_defineNative(&vm.baseClasses->functionClass->methods, ".__str__", _closure_str);
krk_defineNative(&vm.baseClasses->functionClass->methods, ".__repr__", _closure_str);
krk_defineNative(&vm.baseClasses->functionClass->methods, ":__doc__", _closure_get_doc);
krk_defineNative(&vm.baseClasses->functionClass->methods, ":__name__", _closure_get_name);
krk_defineNative(&vm.baseClasses->functionClass->methods, ":__file__", _closure_get_file);
krk_defineNative(&vm.baseClasses->functionClass->methods, ":__args__", _closure_get_argnames);
krk_defineNative(&vm.baseClasses->functionClass->methods, "_ip_to_line", _closure_ip_to_line);
krk_finalizeClass(vm.baseClasses->functionClass);
KrkClass * function = ADD_BASE_CLASS(vm.baseClasses->functionClass, "function", vm.baseClasses->objectClass);
BIND_METHOD(function,__str__);
BIND_METHOD(function,_ip_to_line);
BIND_PROP(function,__doc__);
BIND_PROP(function,__name__);
BIND_PROP(function,__qualname__);
BIND_PROP(function,__file__);
BIND_PROP(function,__args__);
krk_defineNative(&function->methods, ".__repr__", FUNC_NAME(function,__str__));
krk_finalizeClass(function);
ADD_BASE_CLASS(vm.baseClasses->methodClass, "method", vm.baseClasses->objectClass);
krk_defineNative(&vm.baseClasses->methodClass->methods, ".__str__", _bound_str);
krk_defineNative(&vm.baseClasses->methodClass->methods, ".__repr__", _bound_str);
krk_defineNative(&vm.baseClasses->methodClass->methods, ".__doc__", _bound_get_doc);
krk_defineNative(&vm.baseClasses->methodClass->methods, ":__name__", _bound_get_name);
krk_defineNative(&vm.baseClasses->methodClass->methods, ":__file__", _bound_get_file);
krk_defineNative(&vm.baseClasses->methodClass->methods, ":__args__", _bound_get_argnames);
krk_defineNative(&vm.baseClasses->methodClass->methods, "_ip_to_line", _bound_ip_to_line);
krk_finalizeClass(vm.baseClasses->methodClass);
KrkClass * method = ADD_BASE_CLASS(vm.baseClasses->methodClass, "method", vm.baseClasses->objectClass);
BIND_METHOD(method,__str__);
BIND_METHOD(method,_ip_to_line);
BIND_PROP(method,__doc__);
BIND_PROP(method,__name__);
BIND_PROP(method,__qualname__);
BIND_PROP(method,__file__);
BIND_PROP(method,__args__);
krk_defineNative(&method->methods, ".__repr__", FUNC_NAME(method,__str__));
krk_finalizeClass(method);
BUILTIN_FUNCTION("staticmethod", FUNC_NAME(krk,staticmethod), "A static method does not take an implicit self or cls argument.");
BUILTIN_FUNCTION("classmethod", FUNC_NAME(krk,classmethod), "A class method takes an implicit cls argument, instead of self.");

View File

@ -123,10 +123,9 @@ typedef struct {
KrkLocalEntry * localNames;
unsigned char collectsArguments:1;
unsigned char collectsKeywords:1;
unsigned char isClassMethod:1;
unsigned char isGenerator:1;
unsigned char isStaticMethod:1;
struct KrkInstance * globalsContext;
KrkString * qualname;
} KrkFunction;
/**
@ -140,6 +139,8 @@ typedef struct {
KrkFunction * function;
KrkUpvalue ** upvalues;
size_t upvalueCount;
unsigned char isClassMethod:1;
unsigned char isStaticMethod:1;
} KrkClosure;
typedef void (*KrkCleanupCallback)(struct KrkInstance *);

View File

@ -907,9 +907,9 @@ int krk_bindMethod(KrkClass * _class, KrkString * name) {
if (!_class) return 0;
if (IS_NATIVE(method) && ((KrkNative*)AS_OBJECT(method))->isMethod == 2) {
out = AS_NATIVE(method)->function(1, (KrkValue[]){krk_peek(0)}, 0);
} else if (IS_CLOSURE(method) && (AS_CLOSURE(method)->function->isClassMethod)) {
} else if (IS_CLOSURE(method) && (AS_CLOSURE(method)->isClassMethod)) {
out = OBJECT_VAL(krk_newBoundMethod(OBJECT_VAL(_class), AS_OBJECT(method)));
} else if (IS_CLOSURE(method) && (AS_CLOSURE(method)->function->isStaticMethod)) {
} else if (IS_CLOSURE(method) && (AS_CLOSURE(method)->isStaticMethod)) {
out = method;
} else if (IS_CLOSURE(method) || IS_NATIVE(method)) {
out = OBJECT_VAL(krk_newBoundMethod(krk_peek(0), AS_OBJECT(method)));
@ -1744,7 +1744,7 @@ static int valueGetProperty(KrkString * name) {
_class = _class->base;
}
if (_class) {
if (IS_CLOSURE(value) && AS_CLOSURE(value)->function->isClassMethod) {
if (IS_CLOSURE(value) && AS_CLOSURE(value)->isClassMethod) {
value = OBJECT_VAL(krk_newBoundMethod(krk_peek(0), AS_OBJECT(value)));
}
krk_pop();

View File

@ -112,7 +112,7 @@ let test = Test()
test.doAThing()
test.foo = "bar"
print(test.foo)
print(test.doAThing)
print('<bound method Test.doAThing of ' in str(test.doAThing))
test.doAThing()

View File

@ -29,7 +29,7 @@ Let's do some classes.
<class '__main__.Test'>
yay: bax
bar
<bound method Test.doAThing>
True
yay: bar
This is a great teapot!
Subclass says: (I am a teapot)

View File

@ -14,10 +14,10 @@ def noargs():
Foo.other = other
Foo.noargs = noargs
print(f.other)
print('<bound method other' in str(f.other))
f.other()
print(f.noargs)
print('<bound method noargs' in str(f.noargs))
try:
f.noargs()
except Exception as e:

View File

@ -1,6 +1,6 @@
Called bar
<bound method Foo.other>
True
Called other
<bound method Foo.noargs>
True
noargs() takes exactly 0 arguments (1 given)
I can be called

View File

@ -1,4 +1,4 @@
print(*[1,2,3],*['test',object,lambda x: x * 5],7,9,10,end=';\n',**{'sep':', '})
print(*[1,2,3],*['test',object],7,9,10,end=';\n',**{'sep':', '})
let l = [1,2,3]
let d = {'sep': ', '}

View File

@ -1,4 +1,4 @@
1, 2, 3, test, <class 'object'>, <function <lambda>>, 7, 9, 10;
1, 2, 3, test, <class 'object'>, 7, 9, 10;
a, b, 1, 2, 3, 7, 1, 2, 3test
1 apples <class 'object'>
got multiple values for argument 'a'

View File

@ -73,7 +73,7 @@ print("Returned from f.decorated()")
def decoratorWithArgument(decoratorArg):
def theActualDecorator(func):
print("I am decorating",func,"with this argument:",decoratorArg)
print("I am decorating",func.__qualname__,"with this argument:",decoratorArg)
def wrapped():
print("This wrapper captured this decorator arg:", decoratorArg)
func()
@ -88,7 +88,7 @@ decoratedWithArgument()
def methodDecoratorWithArguments(decoratorArgA, decoratorArgB):
def theActualDecorator(method):
print("I am decorating", method, "with these args:", decoratorArgA, decoratorArgB)
print("I am decorating", method.__qualname__, "with these args:", decoratorArgA, decoratorArgB)
def wrapped(instance, wrapperArg):
print("I captured these from the decorator:", decoratorArgA, decoratorArgB)
print("I also take my own argument:", wrapperArg)

View File

@ -22,10 +22,10 @@ I need an extra arg: butts
(decorated) self.foo = bar
Done.
Returned from f.decorated()
I am decorating <function decoratedWithArgument> with this argument: foo
I am decorating decoratedWithArgument with this argument: foo
This wrapper captured this decorator arg: foo
I don't take any args of mine own, and nor does my wrapper.
I am decorating <function superDecoratedMethod> with these args: foo bar
I am decorating Bar.superDecoratedMethod with these args: foo bar
I captured these from the decorator: foo bar
I also take my own argument: this arg goes to the wrapper
I am method, so I can access myself weee and also my own argument which is now and modify this one

View File

@ -4,7 +4,7 @@ def foo(default="bacon"):
print("hello")
return test
print(foo())
print('<function foo.<locals>.test' in str(foo()))
foo("sports")
def fillValues(a=1,b=2,c="c",d=None,e=2.71828):

View File

@ -1,5 +1,5 @@
You like bacon right?
<function test>
True
You like sports right?
1 True c None 2.71828
one 2 test None <class 'object'>

View File

@ -4,11 +4,6 @@ l.append(1)
l.append(2)
l.append("string")
l.append(3.14159)
def foo():
print("bar")
l.append(foo)
l.append("world")
for v in l:

View File

@ -2,5 +2,4 @@
2
string
3.14159
<function foo>
world

View File

@ -1,5 +1,5 @@
Foo: <str>
<str>
<repr>
<bound method Foo.__str__>
<bound method Foo.__repr__>
<bound method Foo.__str__ of <repr>>
<bound method Foo.__repr__ of <repr>>

View File

@ -7,4 +7,4 @@ def テスト(引数="こんにちは"):
let おはよう = "おはようございます!"
テスト(おはよう)
print(テスト)
print('<function テスト' in str(テスト))

View File

@ -1,4 +1,4 @@
ああ、 こんにちは
ああ、 こんばんは!
ああ、 おはようございます!
<function テスト>
True

View File

@ -1 +1 @@
I have a module: <instance of object
I have a module: <object object at 0x