From 26a31b713ec984e826b82207076005da6e5e48ca Mon Sep 17 00:00:00 2001 From: "K. Lange" Date: Wed, 27 Jul 2022 21:42:37 +0900 Subject: [PATCH] Use a custom formatter for krk_runtimeError --- docs/c_functions.md | 2 +- src/builtins.c | 27 ++-- src/debug.c | 4 +- src/kuroko/util.h | 8 +- src/kuroko/vm.h | 26 +++- src/modules/module_math.c | 2 +- src/modules/module_socket.c | 8 +- src/obj_bytes.c | 14 +-- src/obj_dict.c | 11 +- src/obj_gen.c | 4 +- src/obj_list.c | 4 +- src/obj_long.c | 7 +- src/obj_numeric.c | 10 +- src/obj_set.c | 4 +- src/obj_str.c | 12 +- src/obj_tuple.c | 3 +- src/table.c | 2 +- src/vm.c | 242 +++++++++++++++++++++++++++--------- 18 files changed, 260 insertions(+), 130 deletions(-) diff --git a/docs/c_functions.md b/docs/c_functions.md index 770f6cb..0dfa661 100644 --- a/docs/c_functions.md +++ b/docs/c_functions.md @@ -49,7 +49,7 @@ static KrkValue myfunction(int argc, KrkValue argv[], int hasKw) { int myarg; if (argc != 1) return krk_runtimeError(vm.exceptions->argumentError, "myfunction() expects exactly 1 argument, %d given", argc); - if (!IS_INTEGER(argv[0])) return krk_runtimeError(vm.exceptions->typeError, "expected int, not '%s'", krk_typeName(argv[0])); + if (!IS_INTEGER(argv[0])) return krk_runtimeError(vm.exceptions->typeError, "expected int, not '%T'", argv[0]); myarg = AS_INTEGER(argv[0]); diff --git a/src/builtins.c b/src/builtins.c index 68d24a6..ee4c8eb 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -175,7 +175,7 @@ KRK_Method(object,__format__) { if (!IS_STRING(argv[1])) return TYPE_ERROR(str,argv[1]); if (AS_STRING(argv[1])->length != 0) return krk_runtimeError(vm.exceptions->typeError, "Unsupported format string"); KrkClass * type = krk_getType(argv[0]); - if (!type->_tostr) return krk_runtimeError(vm.exceptions->typeError, "'%s' can not be converted to str", krk_typeName(argv[0])); + if (!type->_tostr) return krk_runtimeError(vm.exceptions->typeError, "'%T' can not be converted to str", argv[0]); krk_push(argv[0]); return krk_callDirect(type->_tostr, 1); } @@ -190,7 +190,7 @@ KRK_Function(len) { if (IS_TUPLE(argv[0])) return INTEGER_VAL(AS_TUPLE(argv[0])->values.count); KrkClass * type = krk_getType(argv[0]); - if (!type->_len) return krk_runtimeError(vm.exceptions->typeError, "object of type '%s' has no len()", krk_typeName(argv[0])); + if (!type->_len) return krk_runtimeError(vm.exceptions->typeError, "object of type '%T' has no len()", argv[0]); krk_push(argv[0]); return krk_callDirect(type->_len, 1); @@ -311,7 +311,7 @@ int krk_unpackIterable(KrkValue iterable, void * context, int callback(void *, c } else { KrkClass * type = krk_getType(iterable); if (unlikely(!type->_iter)) { - krk_runtimeError(vm.exceptions->typeError, "'%s' object is not iterable", krk_typeName(iterable)); + krk_runtimeError(vm.exceptions->typeError, "'%T' object is not iterable", iterable); return 1; } @@ -413,7 +413,7 @@ KRK_Method(map,__init__) { for (int i = 2; i < argc; ++i) { KrkClass * type = krk_getType(argv[i]); if (!type->_iter) { - return krk_runtimeError(vm.exceptions->typeError, "'%s' object is not iterable", krk_typeName(argv[i])); + return krk_runtimeError(vm.exceptions->typeError, "'%T' object is not iterable", argv[i]); } krk_push(argv[i]); KrkValue asIter = krk_callDirect(type->_iter, 1); @@ -477,7 +477,7 @@ KRK_Method(zip,__init__) { for (int i = 1; i < argc; ++i) { KrkClass * type = krk_getType(argv[i]); if (!type->_iter) { - return krk_runtimeError(vm.exceptions->typeError, "'%s' object is not iterable", krk_typeName(argv[i])); + return krk_runtimeError(vm.exceptions->typeError, "'%T' object is not iterable", argv[i]); } krk_push(argv[i]); KrkValue asIter = krk_callDirect(type->_iter, 1); @@ -527,7 +527,7 @@ KRK_Method(filter,__init__) { krk_attachNamedValue(&self->fields, "_function", argv[1]); KrkClass * type = krk_getType(argv[2]); if (!type->_iter) { - return krk_runtimeError(vm.exceptions->typeError, "'%s' object is not iterable", krk_typeName(argv[2])); + return krk_runtimeError(vm.exceptions->typeError, "'%T' object is not iterable", argv[2]); } krk_push(argv[2]); KrkValue asIter = krk_callDirect(type->_iter, 1); @@ -593,7 +593,7 @@ KRK_Method(enumerate,__init__) { /* Attach iterator */ KrkClass * type = krk_getType(argv[1]); if (!type->_iter) { - return krk_runtimeError(vm.exceptions->typeError, "'%s' object is not iterable", krk_typeName(argv[1])); + return krk_runtimeError(vm.exceptions->typeError, "'%T' object is not iterable", argv[1]); } krk_push(argv[1]); KrkValue asIter = krk_callDirect(type->_iter, 1); @@ -724,12 +724,12 @@ KRK_Function(print) { char * end = "\n"; size_t endLen = 1; if (hasKw) { if (krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("sep")), &sepVal)) { - if (!IS_STRING(sepVal)) return krk_runtimeError(vm.exceptions->typeError, "'%s' should be a string, not '%s'", "sep", krk_typeName(sepVal)); + if (!IS_STRING(sepVal)) return krk_runtimeError(vm.exceptions->typeError, "'%s' should be a string, not '%T'", "sep", sepVal); sep = AS_CSTRING(sepVal); sepLen = AS_STRING(sepVal)->length; } if (krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("end")), &endVal)) { - if (!IS_STRING(endVal)) return krk_runtimeError(vm.exceptions->typeError, "'%s' should be a string, not '%s'", "end", krk_typeName(endVal)); + if (!IS_STRING(endVal)) return krk_runtimeError(vm.exceptions->typeError, "'%s' should be a string, not '%T'", "end", endVal); end = AS_CSTRING(endVal); endLen = AS_STRING(endVal)->length; } @@ -1037,7 +1037,7 @@ KRK_Method(property,__get__) { KrkValue fget; if (!krk_tableGet(&self->fields, OBJECT_VAL(S("fget")), &fget)) - return krk_runtimeError(vm.exceptions->attributeError, "'%s' object has no attribute '%s'", "property", "fget"); + return krk_runtimeError(vm.exceptions->attributeError, "'%T' object has no attribute '%s'", argv[0], "fget"); krk_push(fget); krk_push(argv[1]); @@ -1068,7 +1068,7 @@ KRK_Method(property,__set__) { KRK_Function(id) { FUNCTION_TAKES_EXACTLY(1); - if (!IS_OBJECT(argv[0])) return krk_runtimeError(vm.exceptions->typeError, "'%s' has no identity", krk_typeName(argv[0])); + if (!IS_OBJECT(argv[0])) return krk_runtimeError(vm.exceptions->typeError, "'%T' has no identity", argv[0]); return INTEGER_VAL((size_t)AS_OBJECT(argv[0])); } @@ -1095,8 +1095,7 @@ KRK_Function(abs) { return FLOATING_VAL(i >= 0 ? i : -i); } else { trySlowMethod(OBJECT_VAL(S("__abs__"))); - return krk_runtimeError(vm.exceptions->typeError, "bad operand type for 'abs()': '%s'", - krk_typeName(argv[0])); + return krk_runtimeError(vm.exceptions->typeError, "bad operand type for 'abs()': '%T'", argv[0]); } } @@ -1107,7 +1106,7 @@ KRK_Function(format) { KrkClass * type = krk_getType(argv[0]); if (!type->_format) { - return krk_runtimeError(vm.exceptions->typeError, "'%s' has no __format__ method", krk_typeName(argv[0])); + return krk_runtimeError(vm.exceptions->typeError, "'%T' has no __format__ method", argv[0]); } krk_push(argv[0]); diff --git a/src/debug.c b/src/debug.c index 4641689..5b6fdc8 100644 --- a/src/debug.c +++ b/src/debug.c @@ -603,7 +603,7 @@ KRK_Function(dis) { krk_disassembleCodeObject(stdout, func, tmp); free(tmp); } else { - krk_runtimeError(vm.exceptions->typeError, "Can not disassemble built-in method of '%s'", krk_typeName(AS_BOUND_METHOD(argv[0])->receiver)); + krk_runtimeError(vm.exceptions->typeError, "Can not disassemble built-in method of '%T'", AS_BOUND_METHOD(argv[0])->receiver); } } else if (IS_CLASS(argv[0])) { KrkValue code; @@ -613,7 +613,7 @@ KRK_Function(dis) { } /* TODO Methods! */ } else { - krk_runtimeError(vm.exceptions->typeError, "Don't know how to disassemble '%s'", krk_typeName(argv[0])); + krk_runtimeError(vm.exceptions->typeError, "Don't know how to disassemble '%T'", argv[0]); } return NONE_VAL(); diff --git a/src/kuroko/util.h b/src/kuroko/util.h index e6ff066..b76d638 100644 --- a/src/kuroko/util.h +++ b/src/kuroko/util.h @@ -25,8 +25,8 @@ #define ADD_BASE_CLASS(obj, name, baseClass) krk_makeClass(vm.builtins, &obj, name, baseClass) -#define ATTRIBUTE_NOT_ASSIGNABLE() do { if (unlikely(argc != 1)) return krk_runtimeError(vm.exceptions->attributeError, "'%s' object has no attribute '%s'", \ - krk_typeName(argv[0]), _method_name); } while (0) +#define ATTRIBUTE_NOT_ASSIGNABLE() do { if (unlikely(argc != 1)) return krk_runtimeError(vm.exceptions->attributeError, "'%T' object has no attribute '%s'", \ + argv[0], _method_name); } while (0) #define METHOD_TAKES_NONE() do { if (unlikely(argc != 1)) return krk_runtimeError(vm.exceptions->argumentError, "%s() takes no arguments (%d given)", \ _method_name, (argc-1)); } while (0) @@ -52,8 +52,8 @@ #define FUNCTION_TAKES_AT_MOST(n) do { if (unlikely(argc > n)) return krk_runtimeError(vm.exceptions->argumentError, "%s() takes %s %d argument%s (%d given)", \ _method_name, "at most", n, (n != 1) ? "s" : "", (argc)); } while (0) -#define TYPE_ERROR(expected,value) krk_runtimeError(vm.exceptions->typeError, "%s() expects %s, not '%s'", \ - /* Function name */ _method_name, /* expected type */ #expected, krk_typeName(value)) +#define TYPE_ERROR(expected,value) krk_runtimeError(vm.exceptions->typeError, "%s() expects %s, not '%T'", \ + /* Function name */ _method_name, /* expected type */ #expected, value) #define NOT_ENOUGH_ARGS(name) krk_runtimeError(vm.exceptions->argumentError, "Expected more args.") diff --git a/src/kuroko/vm.h b/src/kuroko/vm.h index a9e45a3..493534f 100644 --- a/src/kuroko/vm.h +++ b/src/kuroko/vm.h @@ -472,12 +472,25 @@ extern void krk_attachNamedObject(KrkTable * table, const char name[], KrkObj * * The created exception object is attached to the current thread state and * the @c KRK_THREAD_HAS_EXCEPTION flag is set. * + * If the format string is exactly "%V", the first format argument will + * be attached the exception as the 'msg' attribute. + * + * No field width or precisions are supported on any conversion specifiers. + * + * Standard conversion specifiers 'c', 's', 'd', 'u' are available, and the + * 'd' and 'u' specifiers may have length modifiers of l, L, or z. + * + * Additional format specifiers are as follows: + * + * %S - Accepts one KrkString* to be printed in its entirety. + * %R - Accepts one KrkValue and calls repr on it. + * %T - Accepts one KrkValue and emits the name of its type. + * * @param type Class pointer for the exception type, eg. @c vm.exceptions->valueError * @param fmt Format string. * @return As a convenience to C extension authors, returns @c None */ -extern KrkValue krk_runtimeError(KrkClass * type, const char * fmt, ...) - __attribute__((format (printf, 2, 3))); +extern KrkValue krk_runtimeError(KrkClass * type, const char * fmt, ...); /** * @brief Get a pointer to the current thread state. @@ -749,6 +762,9 @@ extern int krk_isFalsey(KrkValue value); * This is a convenience function that works in essentially the * same way as the OP_GET_PROPERTY instruction. * + * @warning As this function takes a C string, it will not work with + * @warning attribute names that have nil bytes. + * * @param value Value to examine. * @param name C-string of the property name to query. * @return The requested property, or None with an @ref AttributeError @@ -769,6 +785,9 @@ extern KrkValue krk_valueGetAttribute_default(KrkValue value, char * name, KrkVa * This is a convenience function that works in essentially the * same way as the OP_SET_PROPERTY instruction. * + * @warning As this function takes a C string, it will not work with + * @warning attribute names that have nil bytes. + * * @param owner The owner of the property to modify. * @param name C-string of the property name to modify. * @param to The value to assign. @@ -785,6 +804,9 @@ extern KrkValue krk_valueSetAttribute(KrkValue owner, char * name, KrkValue to); * This is a convenience function that works in essentially the * same way as the OP_DEL_PROPERTY instruction. * + * @warning As this function takes a C string, it will not work with + * @warning attribute names that have nil bytes. + * * @param owner The owner of the property to delete. * @param name C-string of the property name to delete. */ diff --git a/src/modules/module_math.c b/src/modules/module_math.c index d3f1dc8..ebf6044 100644 --- a/src/modules/module_math.c +++ b/src/modules/module_math.c @@ -34,7 +34,7 @@ } } #define REAL_NUMBER_NOT(name, garbage) { \ - krk_runtimeError(vm.exceptions->typeError, "%s() argument must be real number, not %s", #name, krk_typeName(garbage)); \ + krk_runtimeError(vm.exceptions->typeError, "%s() argument must be real number, not '%T'", #name, garbage); \ return NONE_VAL(); \ } diff --git a/src/modules/module_socket.c b/src/modules/module_socket.c index 927a44f..eeecf2f 100644 --- a/src/modules/module_socket.c +++ b/src/modules/module_socket.c @@ -113,20 +113,20 @@ static int socket_parse_address(struct socket * self, KrkValue address, struct s if (self->family == AF_INET) { /* Should be 2-tuple */ if (!IS_tuple(address)) { - krk_runtimeError(vm.exceptions->typeError, "Expected 2-tuple, not '%s'", krk_typeName(address)); + krk_runtimeError(vm.exceptions->typeError, "Expected 2-tuple, not '%T'", address); return 1; } KrkTuple * addr = AS_TUPLE(address); if (addr->values.count != 2) { - krk_runtimeError(vm.exceptions->typeError, "Expected 2-tuple, not '%s'", krk_typeName(address)); + krk_runtimeError(vm.exceptions->typeError, "Expected 2-tuple, not '%T'", address); return 1; } if (!IS_str(addr->values.values[0])) { - krk_runtimeError(vm.exceptions->typeError, "Address should be int, not '%s'", krk_typeName(addr->values.values[0])); + krk_runtimeError(vm.exceptions->typeError, "Address should be int, not '%T'", addr->values.values[0]); return 1; } if (!IS_int(addr->values.values[1])) { - krk_runtimeError(vm.exceptions->typeError, "Port should be int, not '%s'", krk_typeName(addr->values.values[1])); + krk_runtimeError(vm.exceptions->typeError, "Port should be int, not '%T'", addr->values.values[1]); return 1; } diff --git a/src/obj_bytes.c b/src/obj_bytes.c index cca78ff..4b9a85b 100644 --- a/src/obj_bytes.c +++ b/src/obj_bytes.c @@ -27,8 +27,8 @@ KRK_Method(bytes,__init__) { krk_push(OBJECT_VAL(out)); for (size_t i = 0; i < AS_TUPLE(argv[1])->values.count; ++i) { if (!IS_INTEGER(AS_TUPLE(argv[1])->values.values[i])) { - return krk_runtimeError(vm.exceptions->typeError, "%s() expects %s, not '%s'", - "bytes", "tuple of ints", krk_typeName(AS_TUPLE(argv[1])->values.values[i])); + return krk_runtimeError(vm.exceptions->typeError, "%s() expects %s, not '%T'", + "bytes", "tuple of ints", AS_TUPLE(argv[1])->values.values[i]); } out->bytes[i] = AS_INTEGER(AS_TUPLE(argv[1])->values.values[i]); } @@ -38,8 +38,8 @@ KRK_Method(bytes,__init__) { krk_push(OBJECT_VAL(out)); for (size_t i = 0; i < AS_LIST(argv[1])->count; ++i) { if (!IS_INTEGER(AS_LIST(argv[1])->values[i])) { - return krk_runtimeError(vm.exceptions->typeError, "%s() expects %s, not '%s'", - "bytes", "list of ints", krk_typeName(AS_LIST(argv[1])->values[i])); + return krk_runtimeError(vm.exceptions->typeError, "%s() expects %s, not '%T'", + "bytes", "list of ints", AS_LIST(argv[1])->values[i]); } out->bytes[i] = AS_INTEGER(AS_LIST(argv[1])->values[i]); } @@ -50,7 +50,7 @@ KRK_Method(bytes,__init__) { AS_BYTES(AS_bytearray(argv[1])->actual)->bytes)); } - return krk_runtimeError(vm.exceptions->typeError, "Can not convert '%s' to bytes", krk_typeName(argv[1])); + return krk_runtimeError(vm.exceptions->typeError, "Can not convert '%T' to bytes", argv[1]); } #undef IS_bytes @@ -198,8 +198,8 @@ static int _bytes_join_callback(void * context, const KrkValue * values, size_t for (size_t i = 0; i < count; ++i) { if (!IS_BYTES(values[i])) { - krk_runtimeError(vm.exceptions->typeError, "%s() expects %s, not '%s'", - "join", "bytes", krk_typeName(values[i])); + krk_runtimeError(vm.exceptions->typeError, "%s() expects %s, not '%T'", + "join", "bytes", values[i]); return 1; } diff --git a/src/obj_dict.c b/src/obj_dict.c index 5794c03..0cdfb4a 100644 --- a/src/obj_dict.c +++ b/src/obj_dict.c @@ -4,13 +4,6 @@ #include #include -#define KEY_ERROR(value) {\ - KrkClass * type = krk_getType(value); \ - krk_push(value); \ - KrkValue asString = krk_callDirect(type->_reprer, 1); \ - if (IS_STRING(asString)) return krk_runtimeError(vm.exceptions->keyError, "%s", AS_CSTRING(asString)); \ - return krk_runtimeError(vm.exceptions->keyError, "key error"); } - /** * Exposed method called to produce dictionaries from `{expr: expr, ...}` sequences in managed code. * Expects arguments as `key,value,key,value`... @@ -131,7 +124,7 @@ KRK_Method(dict,__getitem__) { KrkValue out; if (!krk_tableGet(&self->entries, argv[1], &out)) { if (!IS_NONE(krk_currentThread.currentException)) return NONE_VAL(); - KEY_ERROR(argv[1]); + return krk_runtimeError(vm.exceptions->keyError, "%V", argv[1]); } return out; } @@ -156,7 +149,7 @@ KRK_Method(dict,__delitem__) { METHOD_TAKES_EXACTLY(1); if (!krk_tableDelete(&self->entries, argv[1])) { if (!IS_NONE(krk_currentThread.currentException)) return NONE_VAL(); - KEY_ERROR(argv[1]); + return krk_runtimeError(vm.exceptions->keyError, "%V", argv[1]); } return NONE_VAL(); } diff --git a/src/obj_gen.c b/src/obj_gen.c index 125c4ff..ef6ed96 100644 --- a/src/obj_gen.c +++ b/src/obj_gen.c @@ -253,11 +253,11 @@ int krk_getAwaitable(void) { krk_push(krk_callStack(0)); KrkClass * _type = krk_getType(krk_peek(0)); if (!_type || !_type->_iter) { - krk_runtimeError(vm.exceptions->attributeError, "__await__ returned non-iterator of type '%s'", krk_typeName(krk_peek(0))); + krk_runtimeError(vm.exceptions->attributeError, "__await__ returned non-iterator of type '%T'", krk_peek(0)); return 0; } } else { - krk_runtimeError(vm.exceptions->attributeError, "'%s' object is not awaitable", krk_typeName(krk_peek(0))); + krk_runtimeError(vm.exceptions->attributeError, "'%T' object is not awaitable", krk_peek(0)); return 0; } diff --git a/src/obj_list.c b/src/obj_list.c index 67e6f3d..1c23897 100644 --- a/src/obj_list.c +++ b/src/obj_list.c @@ -365,14 +365,14 @@ KRK_Method(list,index) { if (IS_INTEGER(argv[2])) min = AS_INTEGER(argv[2]); else - return krk_runtimeError(vm.exceptions->typeError, "%s must be int, not '%s'", "min", krk_typeName(argv[2])); + return krk_runtimeError(vm.exceptions->typeError, "%s must be int, not '%T'", "min", argv[2]); } if (argc > 3) { if (IS_INTEGER(argv[3])) max = AS_INTEGER(argv[3]); else - return krk_runtimeError(vm.exceptions->typeError, "%s must be int, not '%s'", "max", krk_typeName(argv[3])); + return krk_runtimeError(vm.exceptions->typeError, "%s must be int, not '%T'", "max", argv[3]); } pthread_rwlock_rdlock(&self->rwlock); diff --git a/src/obj_long.c b/src/obj_long.c index bb0754a..5959928 100644 --- a/src/obj_long.c +++ b/src/obj_long.c @@ -1190,15 +1190,12 @@ KRK_Method(long,__init__) { } else if (IS_STRING(argv[1])) { /* XXX This should probably work like int(...) does and default to base 10... and take a base at all... */ if (krk_long_parse_string(AS_CSTRING(argv[1]),self->value,0,AS_STRING(argv[1])->length)) { - krk_push(argv[1]); - KrkValue repred = krk_callDirect(vm.baseClasses->strClass->_reprer, 1); - return krk_runtimeError(vm.exceptions->valueError, "invalid literal for long() with base " PRIkrk_int "%s%s", - (krk_integer_type)0, IS_STRING(repred) ? ": " : "", IS_STRING(repred) ? AS_CSTRING(repred) : ""); + return krk_runtimeError(vm.exceptions->valueError, "invalid literal for long() with base 0: %R", argv[1]); } } else if (IS_long(argv[1])) { krk_long_init_copy(self->value,AS_long(argv[1])->value); } else { - return krk_runtimeError(vm.exceptions->typeError, "%s() argument must be a string or a number, not '%s'", "int", krk_typeName(argv[1])); + return krk_runtimeError(vm.exceptions->typeError, "%s() argument must be a string or a number, not '%T'", "int", argv[1]); } /* our value should be set */ return argv[0]; diff --git a/src/obj_numeric.c b/src/obj_numeric.c index e3eb68f..66feb60 100644 --- a/src/obj_numeric.c +++ b/src/obj_numeric.c @@ -28,16 +28,14 @@ FUNC_SIG(int,__init__) { } KrkValue result = krk_parse_int(AS_CSTRING(argv[1]), AS_STRING(argv[1])->length, _base); if (IS_NONE(result)) { - krk_push(argv[1]); - KrkValue repred = krk_callDirect(vm.baseClasses->strClass->_reprer, 1); - return krk_runtimeError(vm.exceptions->valueError, "invalid literal for int() with base " PRIkrk_int "%s%s", - _base, IS_STRING(repred) ? ": " : "", IS_STRING(repred) ? AS_CSTRING(repred) : ""); + return krk_runtimeError(vm.exceptions->valueError, + "invalid literal for int() with base %zd: %R", (ssize_t)_base, argv[1]); } return result; } if (IS_FLOATING(argv[1])) return INTEGER_VAL(AS_FLOATING(argv[1])); if (IS_BOOLEAN(argv[1])) return INTEGER_VAL(AS_BOOLEAN(argv[1])); - return krk_runtimeError(vm.exceptions->typeError, "%s() argument must be a string or a number, not '%s'", "int", krk_typeName(argv[1])); + return krk_runtimeError(vm.exceptions->typeError, "%s() argument must be a string or a number, not '%T'", "int", argv[1]); } KRK_Method(int,__str__) { @@ -573,7 +571,7 @@ FUNC_SIG(float,__init__) { trySlowMethod(vm.specialMethodNames[METHOD_FLOAT]); - return krk_runtimeError(vm.exceptions->typeError, "%s() argument must be a string or a number, not '%s'", "float", krk_typeName(argv[1])); + return krk_runtimeError(vm.exceptions->typeError, "%s() argument must be a string or a number, not '%T'", "float", argv[1]); } KRK_Method(float,__int__) { return INTEGER_VAL(self); } diff --git a/src/obj_set.c b/src/obj_set.c index 7c0d428..406b57f 100644 --- a/src/obj_set.c +++ b/src/obj_set.c @@ -108,7 +108,7 @@ KRK_Method(set,__and__) { KrkClass * type = krk_getType(argv[1]); if (!type->_contains) - return krk_runtimeError(vm.exceptions->typeError, "unsupported operand types for %s: '%s' and '%s'", "&", "set", krk_typeName(argv[1])); + return krk_runtimeError(vm.exceptions->typeError, "unsupported operand types for %s: '%T' and '%T'", "&", argv[0], argv[1]); for (size_t i = 0; i < self->entries.capacity; ++i) { KrkTableEntry * entry = &self->entries.entries[i]; @@ -136,7 +136,7 @@ KRK_Method(set,__xor__) { KrkClass * type = krk_getType(argv[1]); if (!type->_contains) - return krk_runtimeError(vm.exceptions->typeError, "unsupported operand types for %s: '%s' and '%s'", "&", "set", krk_typeName(argv[1])); + return krk_runtimeError(vm.exceptions->typeError, "unsupported operand types for %s: '%T' and '%T'", "&", argv[0], argv[1]); for (size_t i = 0; i < self->entries.capacity; ++i) { KrkTableEntry * entry = &self->entries.entries[i]; diff --git a/src/obj_str.c b/src/obj_str.c index 2077808..e5223e3 100644 --- a/src/obj_str.c +++ b/src/obj_str.c @@ -41,7 +41,7 @@ KRK_Method(str,__init__) { if (IS_STRING(argv[1])) return argv[1]; /* strings are immutable, so we can just return the arg */ /* Find the type of arg */ krk_push(argv[1]); - if (!krk_getType(argv[1])->_tostr) return krk_runtimeError(vm.exceptions->typeError, "Can not convert %s to str", krk_typeName(argv[1])); + if (!krk_getType(argv[1])->_tostr) return krk_runtimeError(vm.exceptions->typeError, "Can not convert '%T' to str", argv[1]); return krk_callDirect(krk_getType(argv[1])->_tostr, 1); } @@ -423,8 +423,8 @@ static int _str_join_callback(void * context, const KrkValue * values, size_t co for (size_t i = 0; i < count; ++i) { if (!IS_STRING(values[i])) { - krk_runtimeError(vm.exceptions->typeError, "%s() expects %s, not '%s'", - "join", "str", krk_typeName(values[i])); + krk_runtimeError(vm.exceptions->typeError, "%s() expects %s, not '%T'", + "join", "str", values[i]); return 1; } @@ -596,8 +596,7 @@ KRK_Method(str,__mod__) { } else if (IS_FLOATING(arg)) { krk_push(INTEGER_VAL(AS_FLOATING(arg))); } else { - krk_runtimeError(vm.exceptions->typeError, "%%i format: a number is required, not %s", - krk_typeName(arg)); + krk_runtimeError(vm.exceptions->typeError, "%%i format: a number is required, not '%T'", arg); goto _exception; } krk_push(krk_callDirect(krk_getType(arg)->_tostr, 1)); @@ -606,8 +605,7 @@ KRK_Method(str,__mod__) { if (ti >= myTuple->values.count) goto _notEnough; KrkValue arg = myTuple->values.values[ti++]; if (!krk_getType(arg)->_tostr) { - krk_runtimeError(vm.exceptions->typeError, "%%s format: cannot convert %s to string", - krk_typeName(arg)); + krk_runtimeError(vm.exceptions->typeError, "%%s format: cannot convert '%T' to string", arg); goto _exception; } diff --git a/src/obj_tuple.c b/src/obj_tuple.c index 2d74672..a51dee4 100644 --- a/src/obj_tuple.c +++ b/src/obj_tuple.c @@ -177,8 +177,7 @@ KRK_Method(tuple,__add__) { METHOD_TAKES_EXACTLY(1); if (!IS_tuple(argv[1])) return krk_runtimeError(vm.exceptions->typeError, - "can only concatenate tuple (not \"%s\") to tuple", - krk_typeName(argv[1])); + "can only concatenate tuple (not '%T') to tuple", argv[1]); KrkTuple * other = AS_tuple(argv[1]); KrkTuple * out = krk_newTuple(self->values.count + other->values.count); diff --git a/src/table.c b/src/table.c index ad14a91..5ae9646 100644 --- a/src/table.c +++ b/src/table.c @@ -55,7 +55,7 @@ inline int krk_hashValue(KrkValue value, uint32_t *hashOut) { } _unhashable: if (IS_NONE(krk_currentThread.currentException)) - krk_runtimeError(vm.exceptions->typeError, "unhashable type: '%s'", krk_typeName(value)); + krk_runtimeError(vm.exceptions->typeError, "unhashable type: '%T'", value); return 1; } diff --git a/src/vm.c b/src/vm.c index abdc20c..0c9f571 100644 --- a/src/vm.c +++ b/src/vm.c @@ -371,17 +371,132 @@ static void raiseException(KrkValue base, KrkValue cause) { * found in vm.exceptions and are initialized on startup. */ KrkValue krk_runtimeError(KrkClass * type, const char * fmt, ...) { - char buf[1024] = {0}; + KrkValue msg = KWARGS_VAL(0); + struct StringBuilder sb = {0}; + va_list args; va_start(args, fmt); - size_t len = vsnprintf(buf, 1024, fmt, args); + + if (!strcmp(fmt,"%V")) { + msg = va_arg(args, KrkValue); + goto _finish; + } + + for (const char * f = fmt; *f; ++f) { + if (*f != '%') { + pushStringBuilder(&sb, *f); + continue; + } + + /* Unset exception flag if it was already set. */ + if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) { + krk_currentThread.flags &= ~(KRK_THREAD_HAS_EXCEPTION); + } + + ++f; + + int size = ' '; + + if (*f == 'z') size = *f++; + else if (*f == 'l') size = *f++; + else if (*f == 'L') size = *f++; + + switch (*f) { + case 0: break; + case '%': + pushStringBuilder(&sb, '%'); + break; + + case 'c': { + char val = (char)va_arg(args, int); + pushStringBuilder(&sb, val); + break; + } + + case 's': { + const char * c = va_arg(args, const char *); + pushStringBuilderStr(&sb, c, strlen(c)); + break; + } + + case 'u': { + size_t val; + if (size == ' ') { + val = va_arg(args, unsigned int); + } else if (size == 'l') { + val = va_arg(args, unsigned long); + } else if (size == 'L') { + val = va_arg(args, unsigned long long); + } else if (size == 'z') { + val = va_arg(args, size_t); + } + char tmp[100]; + snprintf(tmp, 32, "%zu", val); + pushStringBuilderStr(&sb, tmp, strlen(tmp)); + break; + } + + case 'd': { + ssize_t val; + if (size == ' ') { + val = va_arg(args, int); + } else if (size == 'l') { + val = va_arg(args, long); + } else if (size == 'L') { + val = va_arg(args, long long); + } else if (size == 'z') { + val = va_arg(args, ssize_t); + } + char tmp[100]; + snprintf(tmp, 32, "%zd", val); + pushStringBuilderStr(&sb, tmp, strlen(tmp)); + break; + } + + case 'T': { + KrkValue val = va_arg(args, KrkValue); + const char * typeName = krk_typeName(val); + pushStringBuilderStr(&sb, typeName, strlen(typeName)); + break; + } + + case 'S': { + KrkString * val = va_arg(args, KrkString*); + pushStringBuilderStr(&sb, val->chars, val->length); + break; + } + + case 'R': { + KrkValue val = va_arg(args, KrkValue); + KrkClass * type = krk_getType(val); + if (likely(type->_reprer != NULL)) { + krk_push(val); + KrkValue res = krk_callDirect(type->_reprer, 1); + if (IS_STRING(res)) { + pushStringBuilderStr(&sb, AS_CSTRING(res), AS_STRING(res)->length); + } + } + break; + } + + default: { + va_arg(args, void*); + pushStringBuilderStr(&sb, "(unsupported: ", 14); + pushStringBuilder(&sb, *f); + pushStringBuilder(&sb, ')'); + break; + } + } + } + +_finish: va_end(args); krk_currentThread.flags |= KRK_THREAD_HAS_EXCEPTION; /* Allocate an exception object of the requested type. */ KrkInstance * exceptionObject = krk_newInstance(type); krk_push(OBJECT_VAL(exceptionObject)); - krk_attachNamedValue(&exceptionObject->fields, "arg", OBJECT_VAL(krk_copyString(buf, len))); + krk_attachNamedValue(&exceptionObject->fields, "arg", msg == KWARGS_VAL(0) ? finishStringBuilder(&sb) : msg); krk_attachNamedValue(&exceptionObject->fields, "__cause__", NONE_VAL()); krk_attachNamedValue(&exceptionObject->fields, "__context__", NONE_VAL()); krk_pop(); @@ -658,11 +773,11 @@ static inline int checkArgumentCount(const KrkClosure * closure, int argCount) { } static void multipleDefs(const KrkClosure * closure, int destination) { - krk_runtimeError(vm.exceptions->typeError, "%s() got multiple values for argument '%s'", + krk_runtimeError(vm.exceptions->typeError, "%s() got multiple values for argument '%S'", closure->function->name ? closure->function->name->chars : "", - (destination < closure->function->requiredArgs ? AS_CSTRING(closure->function->requiredArgNames.values[destination]) : - (destination - closure->function->requiredArgs < closure->function->keywordArgs ? AS_CSTRING(closure->function->keywordArgNames.values[destination - closure->function->requiredArgs]) : - ""))); + (destination < closure->function->requiredArgs ? AS_STRING(closure->function->requiredArgNames.values[destination]) : + (destination - closure->function->requiredArgs < closure->function->keywordArgs ? AS_STRING(closure->function->keywordArgNames.values[destination - closure->function->requiredArgs]) : + S("")))); } static int _unpack_op(void * context, const KrkValue * values, size_t count) { @@ -725,7 +840,7 @@ int krk_processComplexArguments(int argCount, KrkValueArray * positionals, KrkTa return 0; } if (!krk_tableSet(keywords, entry->key, entry->value)) { - krk_runtimeError(vm.exceptions->typeError, "%s() got multiple values for argument '%s'", name, AS_CSTRING(entry->key)); + krk_runtimeError(vm.exceptions->typeError, "%s() got multiple values for argument '%S'", name, AS_STRING(entry->key)); return 0; } } @@ -735,7 +850,7 @@ int krk_processComplexArguments(int argCount, KrkValueArray * positionals, KrkTa } } else if (IS_STRING(key)) { if (!krk_tableSet(keywords, key, value)) { - krk_runtimeError(vm.exceptions->typeError, "%s() got multiple values for argument '%s'", name, AS_CSTRING(key)); + krk_runtimeError(vm.exceptions->typeError, "%s() got multiple values for argument '%S'", name, AS_STRING(key)); return 0; } } @@ -855,9 +970,9 @@ static inline int _callManaged(KrkClosure * closure, int argCount, int returnDep } } if (!(closure->function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS)) { - krk_runtimeError(vm.exceptions->typeError, "%s() got an unexpected keyword argument '%s'", + krk_runtimeError(vm.exceptions->typeError, "%s() got an unexpected keyword argument '%S'", closure->function->name ? closure->function->name->chars : "", - AS_CSTRING(name)); + AS_STRING(name)); goto _errorAfterPositionals; } continue; @@ -880,9 +995,9 @@ _finishKwarg: for (size_t i = 0; i < (size_t)closure->function->requiredArgs; ++i) { if (IS_KWARGS(krk_currentThread.stackTop[-argCount + i])) { - krk_runtimeError(vm.exceptions->typeError, "%s() missing required positional argument: '%s'", + krk_runtimeError(vm.exceptions->typeError, "%s() missing required positional argument: '%S'", closure->function->name ? closure->function->name->chars : "", - AS_CSTRING(closure->function->requiredArgNames.values[i])); + AS_STRING(closure->function->requiredArgNames.values[i])); goto _errorAfterKeywords; } } @@ -1041,7 +1156,7 @@ int krk_callValue(KrkValue callee, int argCount, int returnDepth) { returnDepth = returnDepth ? (returnDepth - 1) : 0; return (_class->_call->type == KRK_OBJ_CLOSURE) ? _callManaged((KrkClosure*)_class->_call, argCount, returnDepth) : _callNative((KrkNative*)_class->_call, argCount, returnDepth); } else { - krk_runtimeError(vm.exceptions->typeError, "'%s' object is not callable", krk_typeName(callee)); + krk_runtimeError(vm.exceptions->typeError, "'%T' object is not callable", callee); return 0; } } @@ -1056,8 +1171,8 @@ int krk_callValue(KrkValue callee, int argCount, int returnDepth) { returnDepth = returnDepth ? (returnDepth - 1) : 0; goto _innerObject; } else if (unlikely(argCount != 0)) { - krk_runtimeError(vm.exceptions->typeError, "%s() takes no arguments (%d given)", - _class->name->chars, argCount); + krk_runtimeError(vm.exceptions->typeError, "%S() takes no arguments (%d given)", + _class->name, argCount); return 0; } krk_currentThread.stackTop -= argCount + returnDepth; @@ -1081,7 +1196,7 @@ int krk_callValue(KrkValue callee, int argCount, int returnDepth) { break; } } - krk_runtimeError(vm.exceptions->typeError, "'%s' object is not callable", krk_typeName(callee)); + krk_runtimeError(vm.exceptions->typeError, "'%T' object is not callable", callee); return 0; } @@ -1676,8 +1791,8 @@ const char * krk_typeName(KrkValue value) { } \ if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL(); \ return krk_runtimeError(vm.exceptions->typeError, \ - "unsupported operand types for %s: '%s' and '%s'", \ - operator, krk_typeName(a), krk_typeName(b)); \ + "unsupported operand types for %s: '%T' and '%T'", \ + operator, a, b); \ } #define MAKE_BIN_OP(name,operator,inv) \ MAKE_COMPARE_OP(name,operator,inv) \ @@ -1729,7 +1844,7 @@ KrkValue krk_operator_is(KrkValue a, KrkValue b) { return krk_callDirect(type-> sname, 1); \ } \ if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL(); \ - return krk_runtimeError(vm.exceptions->typeError, "bad operand type for unary %s: '%s'", #op, krk_typeName(value)); \ + return krk_runtimeError(vm.exceptions->typeError, "bad operand type for unary %s: '%T'", #op, value); \ } MAKE_UNARY_OP(_invert,invert,~) @@ -1871,8 +1986,8 @@ int krk_loadModule(KrkString * path, KrkValue * moduleOut, KrkString * runAs, Kr /* Try to import that. */ KrkValue dotted_main = krk_peek(0); if (!krk_importModule(AS_STRING(dotted_main),runAs)) { - krk_runtimeError(vm.exceptions->importError, "No module named %s; '%s' is a package and cannot be executed directly", - AS_CSTRING(dotted_main), AS_CSTRING(packageName)); + krk_runtimeError(vm.exceptions->importError, "No module named '%S'; '%S' is a package and cannot be executed directly", + AS_STRING(dotted_main), AS_STRING(packageName)); return 0; } @@ -1955,7 +2070,7 @@ int krk_loadModule(KrkString * path, KrkValue * moduleOut, KrkString * runAs, Kr if (!dlRef) { *moduleOut = NONE_VAL(); krk_runtimeError(vm.exceptions->importError, - "Failed to load native module '%s' from shared object '%s'", runAs->chars, fileName); + "Failed to load native module '%S' from shared object '%s'", runAs, fileName); return 0; } @@ -1989,7 +2104,7 @@ int krk_loadModule(KrkString * path, KrkValue * moduleOut, KrkString * runAs, Kr if (!krk_isInstanceOf(*moduleOut, vm.baseClasses->moduleClass)) { dlClose(dlRef); krk_runtimeError(vm.exceptions->importError, - "Failed to load module '%s' from '%s'", runAs->chars, fileName); + "Failed to load module '%S' from '%s'", runAs, fileName); return 0; } @@ -2024,7 +2139,7 @@ int krk_loadModule(KrkString * path, KrkValue * moduleOut, KrkString * runAs, Kr krk_push(OBJECT_VAL(runAs)); } - krk_runtimeError(vm.exceptions->importError, "No module named '%s'", AS_CSTRING(krk_peek(0))); + krk_runtimeError(vm.exceptions->importError, "No module named '%S'", AS_STRING(krk_peek(0))); return 0; } @@ -2205,7 +2320,7 @@ int krk_importModule(KrkString * name, KrkString * runAs) { /* Is this a package? */ KrkValue tmp; if (!krk_tableGet_fast(&AS_INSTANCE(current)->fields, S("__ispackage__"), &tmp) || !IS_BOOLEAN(tmp) || AS_BOOLEAN(tmp) != 1) { - krk_runtimeError(vm.exceptions->importError, "'%s' is not a package", AS_CSTRING(krk_currentThread.stack[argBase+2])); + krk_runtimeError(vm.exceptions->importError, "'%S' is not a package", AS_STRING(krk_currentThread.stack[argBase+2])); return 0; } krk_currentThread.stack[argBase-1] = krk_pop(); @@ -2336,15 +2451,17 @@ static int valueGetMethod(KrkString * name) { } return 0; - } +int krk_getAttribute(KrkString * name) { + return valueGetProperty(name); +} KrkValue krk_valueGetAttribute(KrkValue value, char * name) { krk_push(OBJECT_VAL(krk_copyString(name,strlen(name)))); krk_push(value); if (!valueGetProperty(AS_STRING(krk_peek(1)))) { - return krk_runtimeError(vm.exceptions->attributeError, "'%s' object has no attribute '%s'", krk_typeName(krk_peek(0)), name); + return krk_runtimeError(vm.exceptions->attributeError, "'%T' object has no attribute '%s'", krk_peek(0), name); } krk_swap(1); krk_pop(); /* String */ @@ -2387,11 +2504,15 @@ static int valueDelProperty(KrkString * name) { return 0; } +int krk_delAttribute(KrkString * name) { + return valueDelProperty(name); +} + KrkValue krk_valueDelAttribute(KrkValue owner, char * name) { krk_push(OBJECT_VAL(krk_copyString(name,strlen(name)))); krk_push(owner); if (!valueDelProperty(AS_STRING(krk_peek(1)))) { - return krk_runtimeError(vm.exceptions->attributeError, "'%s' object has no attribute '%s'", krk_typeName(krk_peek(0)), name); + return krk_runtimeError(vm.exceptions->attributeError, "'%T' object has no attribute '%s'", krk_peek(0), name); } krk_pop(); /* String */ return NONE_VAL(); @@ -2486,12 +2607,16 @@ static int valueSetProperty(KrkString * name) { return 1; } +int krk_setAttribute(KrkString * name) { + return valueSetProperty(name); +} + KrkValue krk_valueSetAttribute(KrkValue owner, char * name, KrkValue to) { krk_push(OBJECT_VAL(krk_copyString(name,strlen(name)))); krk_push(owner); krk_push(to); if (!valueSetProperty(AS_STRING(krk_peek(2)))) { - return krk_runtimeError(vm.exceptions->attributeError, "'%s' object has no attribute '%s'", krk_typeName(krk_peek(1)), name); + return krk_runtimeError(vm.exceptions->attributeError, "'%T' object has no attribute '%s'", krk_peek(1), name); } krk_swap(1); krk_pop(); /* String */ @@ -2564,7 +2689,7 @@ static inline int doFormatString(int options) { if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) return 1; } else { krk_runtimeError(vm.exceptions->typeError, - "Can not convert %s to str", krk_typeName(krk_peek(0))); + "Can not convert '%T' to str", krk_peek(0)); return 1; } } else if (options & FORMAT_OP_REPR) { @@ -2574,7 +2699,7 @@ static inline int doFormatString(int options) { if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) return 1; } else { krk_runtimeError(vm.exceptions->typeError, - "Can not repr %s", krk_typeName(krk_peek(0))); + "Can not repr '%T'", krk_peek(0)); return 1; } } @@ -2594,7 +2719,7 @@ static inline int doFormatString(int options) { krk_push(krk_callDirect(type->_format, 2)); if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) return 1; } else { - krk_runtimeError(vm.exceptions->attributeError, "'%s' object has no attribute '%s'", krk_typeName(krk_peek(1)), "__format__"); + krk_runtimeError(vm.exceptions->attributeError, "'%T' object has no attribute '%s'", krk_peek(1), "__format__"); return 1; } @@ -2612,7 +2737,7 @@ static inline void commonMethodInvoke(size_t methodOffset, int args, const char if (likely(method != NULL)) { krk_push(krk_callDirect(method, args)); } else { - krk_runtimeError(vm.exceptions->attributeError, msgFormat, krk_typeName(krk_peek(args-1))); + krk_runtimeError(vm.exceptions->attributeError, msgFormat, krk_peek(args-1)); } } @@ -2790,25 +2915,25 @@ _finishReturn: (void)0; krk_pop(); break; case OP_INVOKE_GETTER: { - commonMethodInvoke(offsetof(KrkClass,_getter), 2, "'%s' object is not subscriptable"); + commonMethodInvoke(offsetof(KrkClass,_getter), 2, "'%T' object is not subscriptable"); break; } case OP_INVOKE_SETTER: { - commonMethodInvoke(offsetof(KrkClass,_setter), 3, "'%s' object doesn't support item assignment"); + commonMethodInvoke(offsetof(KrkClass,_setter), 3, "'%T' object doesn't support item assignment"); break; } case OP_INVOKE_DELETE: { - commonMethodInvoke(offsetof(KrkClass,_delitem), 2, "'%s' object doesn't support item deletion"); + commonMethodInvoke(offsetof(KrkClass,_delitem), 2, "'%T' object doesn't support item deletion"); krk_pop(); /* unused result */ break; } case OP_INVOKE_ITER: { - commonMethodInvoke(offsetof(KrkClass,_iter), 1, "'%s' object is not iterable"); + commonMethodInvoke(offsetof(KrkClass,_iter), 1, "'%T' object is not iterable"); break; } case OP_INVOKE_CONTAINS: { krk_swap(1); /* operands are backwards */ - commonMethodInvoke(offsetof(KrkClass,_contains), 2, "'%s' object can not be tested for membership"); + commonMethodInvoke(offsetof(KrkClass,_contains), 2, "'%T' object can not be tested for membership"); break; } case OP_INVOKE_AWAIT: { @@ -2826,13 +2951,12 @@ _finishReturn: (void)0; case OP_INHERIT: { KrkValue superclass = krk_peek(0); if (unlikely(!IS_CLASS(superclass))) { - krk_runtimeError(vm.exceptions->typeError, "Superclass must be a class, not '%s'", - krk_typeName(superclass)); + krk_runtimeError(vm.exceptions->typeError, "Superclass must be a class, not '%T'", superclass); goto _finishException; } if (AS_OBJECT(superclass)->flags & KRK_OBJ_FLAGS_NO_INHERIT) { - krk_runtimeError(vm.exceptions->typeError, "'%s' can not be subclassed", - AS_CLASS(superclass)->name->chars); + krk_runtimeError(vm.exceptions->typeError, "'%S' can not be subclassed", + AS_CLASS(superclass)->name); goto _finishException; } KrkClass * subclass = AS_CLASS(krk_peek(1)); @@ -2932,7 +3056,7 @@ _finishReturn: (void)0; krk_swap(1); krk_pop(); } else { - krk_runtimeError(vm.exceptions->typeError, "Can not annotate '%s'.", krk_typeName(krk_peek(0))); + krk_runtimeError(vm.exceptions->typeError, "Can not annotate '%T'.", krk_peek(0)); goto _finishException; } break; @@ -3079,7 +3203,7 @@ _finishReturn: (void)0; KrkValue value; if (!krk_tableGet_fast(frame->globals, name, &value)) { if (!krk_tableGet_fast(&vm.builtins->fields, name, &value)) { - krk_runtimeError(vm.exceptions->nameError, "Undefined variable '%s'.", name->chars); + krk_runtimeError(vm.exceptions->nameError, "Undefined variable '%S'.", name); goto _finishException; } } @@ -3092,7 +3216,7 @@ _finishReturn: (void)0; ONE_BYTE_OPERAND; KrkString * name = READ_STRING(OPERAND); if (!krk_tableSetIfExists(frame->globals, OBJECT_VAL(name), krk_peek(0))) { - krk_runtimeError(vm.exceptions->nameError, "Undefined variable '%s'.", name->chars); + krk_runtimeError(vm.exceptions->nameError, "Undefined variable '%S'.", name); goto _finishException; } break; @@ -3103,7 +3227,7 @@ _finishReturn: (void)0; ONE_BYTE_OPERAND; KrkString * name = READ_STRING(OPERAND); if (!krk_tableDelete(frame->globals, OBJECT_VAL(name))) { - krk_runtimeError(vm.exceptions->nameError, "Undefined variable '%s'.", name->chars); + krk_runtimeError(vm.exceptions->nameError, "Undefined variable '%S'.", name); goto _finishException; } break; @@ -3222,7 +3346,7 @@ _finishReturn: (void)0; /* Try to import... */ KrkValue moduleName; if (!krk_tableGet(&AS_INSTANCE(krk_peek(0))->fields, vm.specialMethodNames[METHOD_NAME], &moduleName)) { - krk_runtimeError(vm.exceptions->importError, "Can not import '%s' from non-module '%s' object", name->chars, krk_typeName(krk_peek(0))); + krk_runtimeError(vm.exceptions->importError, "Can not import '%S' from non-module '%T' object", name, krk_peek(0)); goto _finishException; } krk_push(moduleName); @@ -3231,7 +3355,7 @@ _finishReturn: (void)0; krk_push(OBJECT_VAL(name)); krk_addObjects(); if (!krk_doRecursiveModuleLoad(AS_STRING(krk_peek(0)))) { - krk_runtimeError(vm.exceptions->importError, "Can not import '%s' from '%s'", name->chars, AS_CSTRING(moduleName)); + krk_runtimeError(vm.exceptions->importError, "Can not import '%S' from '%S'", name, AS_STRING(moduleName)); goto _finishException; } krk_currentThread.stackTop[-3] = krk_currentThread.stackTop[-1]; @@ -3244,7 +3368,7 @@ _finishReturn: (void)0; ONE_BYTE_OPERAND; KrkString * name = READ_STRING(OPERAND); if (unlikely(!valueGetProperty(name))) { - krk_runtimeError(vm.exceptions->attributeError, "'%s' object has no attribute '%s'", krk_typeName(krk_peek(0)), name->chars); + krk_runtimeError(vm.exceptions->attributeError, "'%T' object has no attribute '%S'", krk_peek(0), name); goto _finishException; } break; @@ -3255,7 +3379,7 @@ _finishReturn: (void)0; ONE_BYTE_OPERAND; KrkString * name = READ_STRING(OPERAND); if (unlikely(!valueDelProperty(name))) { - krk_runtimeError(vm.exceptions->attributeError, "'%s' object has no attribute '%s'", krk_typeName(krk_peek(0)), name->chars); + krk_runtimeError(vm.exceptions->attributeError, "'%T' object has no attribute '%S'", krk_peek(0), name); goto _finishException; } break; @@ -3266,7 +3390,7 @@ _finishReturn: (void)0; ONE_BYTE_OPERAND; KrkString * name = READ_STRING(OPERAND); if (unlikely(!valueSetProperty(name))) { - krk_runtimeError(vm.exceptions->attributeError, "'%s' object has no attribute '%s'", krk_typeName(krk_peek(1)), name->chars); + krk_runtimeError(vm.exceptions->attributeError, "'%T' object has no attribute '%S'", krk_peek(1), name); goto _finishException; } break; @@ -3293,7 +3417,7 @@ _finishReturn: (void)0; KrkValue baseClass = krk_peek(1); if (!IS_CLASS(baseClass)) { krk_runtimeError(vm.exceptions->typeError, - "super() argument 1 must be class, not %s", krk_typeName(baseClass)); + "super() argument 1 must be class, not %T", baseClass); goto _finishException; } if (IS_KWARGS(krk_peek(0))) { @@ -3303,14 +3427,14 @@ _finishReturn: (void)0; } if (!krk_isInstanceOf(krk_peek(0), AS_CLASS(baseClass))) { krk_runtimeError(vm.exceptions->typeError, - "'%s' object is not an instance of '%s'", - krk_typeName(krk_peek(0)), AS_CLASS(baseClass)->name->chars); + "'%T' object is not an instance of '%S'", + krk_peek(0), AS_CLASS(baseClass)->name); goto _finishException; } KrkClass * superclass = AS_CLASS(baseClass)->base ? AS_CLASS(baseClass)->base : vm.baseClasses->objectClass; if (!krk_bindMethod(superclass, name)) { - krk_runtimeError(vm.exceptions->attributeError, "'%s' object has no attribute '%s'", - superclass->name->chars, name->chars); + krk_runtimeError(vm.exceptions->attributeError, "'%S' object has no attribute '%S'", + superclass->name, name); goto _finishException; } /* Swap bind and superclass */ @@ -3330,7 +3454,7 @@ _finishReturn: (void)0; krk_swap(2); krk_pop(); } else if (unlikely(!result)) { - krk_runtimeError(vm.exceptions->attributeError, "'%s' object has no attribute '%s'", krk_typeName(krk_peek(0)), name->chars); + krk_runtimeError(vm.exceptions->attributeError, "'%T' object has no attribute '%S'", krk_peek(0), name); goto _finishException; } else { krk_swap(1); /* unbound-method object */ @@ -3493,7 +3617,7 @@ _finishReturn: (void)0; KrkValue s = krk_currentThread.stackTop[-(ssize_t)OPERAND+i]; if (unlikely(!IS_STRING(s))) { discardStringBuilder(&sb); - krk_runtimeError(vm.exceptions->valueError, "'%s' is not a string", krk_typeName(s)); + krk_runtimeError(vm.exceptions->valueError, "'%T' is not a string", s); goto _finishException; } pushStringBuilderStr(&sb, (char*)AS_STRING(s)->chars, AS_STRING(s)->length);