Fix up function, object repring and add __qualname__ to functions
This commit is contained in:
parent
1201dc8115
commit
f655ca7f61
@ -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);
|
||||
|
@ -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` */
|
||||
|
@ -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.");
|
||||
|
@ -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 *);
|
||||
|
6
src/vm.c
6
src/vm.c
@ -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();
|
||||
|
@ -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()
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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': ', '}
|
||||
|
@ -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'
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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'>
|
||||
|
@ -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:
|
||||
|
@ -2,5 +2,4 @@
|
||||
2
|
||||
string
|
||||
3.14159
|
||||
<function foo>
|
||||
world
|
||||
|
@ -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>>
|
||||
|
@ -7,4 +7,4 @@ def テスト(引数="こんにちは"):
|
||||
let おはよう = "おはようございます!"
|
||||
テスト(おはよう)
|
||||
|
||||
print(テスト)
|
||||
print('<function テスト' in str(テスト))
|
||||
|
@ -1,4 +1,4 @@
|
||||
ああ、 こんにちは
|
||||
ああ、 こんばんは!
|
||||
ああ、 おはようございます!
|
||||
<function テスト>
|
||||
True
|
||||
|
@ -1 +1 @@
|
||||
I have a module: <instance of object
|
||||
I have a module: <object object at 0x
|
||||
|
Loading…
Reference in New Issue
Block a user