diff --git a/src/builtins.c b/src/builtins.c index 1137398..795adbb 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -79,8 +79,8 @@ KrkValue krk_dirObject(int argc, KrkValue argv[], int hasKw) { } -static KrkValue _len(int argc, KrkValue argv[], int hasKw) { - if (argc != 1) return krk_runtimeError(vm.exceptions->argumentError, "len() takes exactly one argument"); +KRK_FUNC(len,{ + FUNCTION_TAKES_EXACTLY(1); /* Shortcuts */ if (IS_STRING(argv[0])) return INTEGER_VAL(AS_STRING(argv[0])->codesLength); if (IS_TUPLE(argv[0])) return INTEGER_VAL(AS_TUPLE(argv[0])->values.count); @@ -90,66 +90,63 @@ static KrkValue _len(int argc, KrkValue argv[], int hasKw) { krk_push(argv[0]); return krk_callSimple(OBJECT_VAL(type->_len), 1, 0); -} +}) -static KrkValue _dir(int argc, KrkValue argv[], int hasKw) { - if (argc != 1) return krk_runtimeError(vm.exceptions->argumentError, "dir() takes exactly one argument"); +KRK_FUNC(dir,{ + FUNCTION_TAKES_EXACTLY(1); KrkClass * type = krk_getType(argv[0]); if (!type->_dir) { return krk_dirObject(argc,argv,hasKw); /* Fallback */ } krk_push(argv[0]); return krk_callSimple(OBJECT_VAL(type->_dir), 1, 0); -} - -static KrkValue _repr(int argc, KrkValue argv[], int hasKw) { - if (argc != 1) return krk_runtimeError(vm.exceptions->argumentError, "repr() takes exactly one argument"); +}) +KRK_FUNC(repr,{ + FUNCTION_TAKES_EXACTLY(1); /* Everything should have a __repr__ */ KrkClass * type = krk_getType(argv[0]); krk_push(argv[0]); return krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0); -} - -static KrkValue _ord(int argc, KrkValue argv[], int hasKw) { - if (argc != 1) return krk_runtimeError(vm.exceptions->argumentError, "ord() takes exactly one argument"); +}) +KRK_FUNC(ord,{ + FUNCTION_TAKES_EXACTLY(1); KrkClass * type = krk_getType(argv[0]); KrkValue method; if (krk_tableGet(&type->methods, vm.specialMethodNames[METHOD_ORD], &method)) { krk_push(argv[0]); return krk_callSimple(method, 1, 0); } - return krk_runtimeError(vm.exceptions->argumentError, "ord() expected string of length 1, but got %s", krk_typeName(argv[0])); -} - -static KrkValue _chr(int argc, KrkValue argv[], int hasKw) { - if (argc != 1) return krk_runtimeError(vm.exceptions->argumentError, "chr() takes exactly one argument"); + return TYPE_ERROR(string of length 1,argv[0]); +}) +KRK_FUNC(chr,{ + FUNCTION_TAKES_EXACTLY(1); KrkClass * type = krk_getType(argv[0]); KrkValue method; if (krk_tableGet(&type->methods, vm.specialMethodNames[METHOD_CHR], &method)) { krk_push(argv[0]); return krk_callSimple(method, 1, 0); } - return krk_runtimeError(vm.exceptions->argumentError, "chr() expected an integer, but got %s", krk_typeName(argv[0])); -} + return TYPE_ERROR(int,argv[0]); +}) -static KrkValue _hex(int argc, KrkValue argv[], int hasKw) { - if (argc != 1 || !IS_INTEGER(argv[0])) return krk_runtimeError(vm.exceptions->argumentError, "hex() expects one int argument"); +KRK_FUNC(hex,{ + FUNCTION_TAKES_EXACTLY(1); + CHECK_ARG(0,int,krk_integer_type,x); char tmp[20]; - krk_integer_type x = AS_INTEGER(argv[0]); size_t len = snprintf(tmp, 20, "%s0x" PRIkrk_hex, x < 0 ? "-" : "", x < 0 ? -x : x); return OBJECT_VAL(krk_copyString(tmp,len)); -} +}) -static KrkValue _oct(int argc, KrkValue argv[], int hasKw) { - if (argc != 1 || !IS_INTEGER(argv[0])) return krk_runtimeError(vm.exceptions->argumentError, "oct() expects one int argument"); +KRK_FUNC(oct,{ + FUNCTION_TAKES_EXACTLY(1); + CHECK_ARG(0,int,krk_integer_type,x); char tmp[20]; - krk_integer_type x = AS_INTEGER(argv[0]); size_t len = snprintf(tmp, 20, "%s0o%llo", x < 0 ? "-" : "", x < 0 ? (long long int)-x : (long long int)x); return OBJECT_VAL(krk_copyString(tmp,len)); -} +}) KRK_FUNC(bin,{ FUNCTION_TAKES_EXACTLY(1); @@ -180,27 +177,29 @@ KRK_FUNC(bin,{ return finishStringBuilder(&sb); }) -static KrkValue _any(int argc, KrkValue argv[], int hasKw) { #define unpackArray(counter, indexer) do { \ for (size_t i = 0; i < counter; ++i) { \ if (!krk_isFalsey(indexer)) return BOOLEAN_VAL(1); \ } \ } while (0) +KRK_FUNC(any,{ + FUNCTION_TAKES_EXACTLY(1); unpackIterableFast(argv[0]); -#undef unpackArray return BOOLEAN_VAL(0); -} +}) +#undef unpackArray -static KrkValue _all(int argc, KrkValue argv[], int hasKw) { #define unpackArray(counter, indexer) do { \ for (size_t i = 0; i < counter; ++i) { \ if (krk_isFalsey(indexer)) return BOOLEAN_VAL(0); \ } \ } while (0) +KRK_FUNC(all,{ + FUNCTION_TAKES_EXACTLY(1); unpackIterableFast(argv[0]); -#undef unpackArray return BOOLEAN_VAL(1); -} +}) +#undef unpackArray static KrkClass * mapobject; KRK_FUNC(map,{ @@ -428,25 +427,23 @@ KRK_METHOD(enumerateobject,__repr__,{ return OBJECT_VAL(krk_copyString(tmp,len)); }) -static KrkValue _sum(int argc, KrkValue argv[], int hasKw) { - KrkValue base = INTEGER_VAL(0); - if (hasKw) { - krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("start")), &base); - } #define unpackArray(counter, indexer) do { \ for (size_t i = 0; i < counter; ++i) { \ base = krk_operator_add(base, indexer); \ } \ } while (0) +KRK_FUNC(sum,{ + FUNCTION_TAKES_AT_LEAST(1); + KrkValue base = INTEGER_VAL(0); + if (hasKw) { + krk_tableGet(AS_DICT(argv[argc]), OBJECT_VAL(S("start")), &base); + } unpackIterableFast(argv[0]); -#undef unpackArray return base; -} +}) +#undef unpackArray extern KrkValue krk_operator_lt(KrkValue a, KrkValue b); -static KrkValue _min(int argc, KrkValue argv[], int hasKw) { - if (argc == 0) return krk_runtimeError(vm.exceptions->argumentError, "expected at least one argument"); - KrkValue base = KWARGS_VAL(0); #define unpackArray(counter, indexer) do { \ for (size_t i = 0; i < counter; ++i) { \ if (IS_KWARGS(base)) base = indexer; \ @@ -457,20 +454,20 @@ static KrkValue _min(int argc, KrkValue argv[], int hasKw) { } \ } \ } while (0) +KRK_FUNC(min,{ + FUNCTION_TAKES_AT_LEAST(1); + KrkValue base = KWARGS_VAL(0); if (argc > 1) { unpackArray((size_t)argc,argv[i]); } else { unpackIterableFast(argv[0]); } -#undef unpackArray - if (IS_KWARGS(base)) return krk_runtimeError(vm.exceptions->valueError, "empty argument to min()"); + if (IS_KWARGS(base)) return krk_runtimeError(vm.exceptions->valueError, "empty argument to %s()", "min"); return base; -} +}) +#undef unpackArray extern KrkValue krk_operator_gt(KrkValue a, KrkValue b); -static KrkValue _max(int argc, KrkValue argv[], int hasKw) { - if (argc == 0) return krk_runtimeError(vm.exceptions->argumentError, "expected at least one argument"); - KrkValue base = KWARGS_VAL(0); #define unpackArray(counter, indexer) do { \ for (size_t i = 0; i < counter; ++i) { \ if (IS_KWARGS(base)) base = indexer; \ @@ -481,15 +478,18 @@ static KrkValue _max(int argc, KrkValue argv[], int hasKw) { } \ } \ } while (0) +KRK_FUNC(max,{ + FUNCTION_TAKES_AT_LEAST(1); + KrkValue base = KWARGS_VAL(0); if (argc > 1) { unpackArray((size_t)argc,argv[i]); } else { unpackIterableFast(argv[0]); } -#undef unpackArray - if (IS_KWARGS(base)) return krk_runtimeError(vm.exceptions->valueError, "empty argument to max()"); + if (IS_KWARGS(base)) return krk_runtimeError(vm.exceptions->valueError, "empty argument to %s()", "max"); return base; -} +}) +#undef unpackArray static KrkValue _print(int argc, KrkValue argv[], int hasKw) { KrkValue sepVal, endVal; @@ -530,7 +530,8 @@ static KrkValue _print(int argc, KrkValue argv[], int hasKw) { * * Returns a dict of names -> values for all the globals. */ -static KrkValue _globals(int argc, KrkValue argv[], int hasKw) { +KRK_FUNC(globals,{ + FUNCTION_TAKES_NONE(); /* Make a new empty dict */ KrkValue dict = krk_dict_of(0, NULL, 0); krk_push(dict); @@ -539,14 +540,15 @@ static KrkValue _globals(int argc, KrkValue argv[], int hasKw) { krk_pop(); return dict; -} +}) /** * locals() * * This is a bit trickier. Local names are... complicated. But we can do this! */ -static KrkValue _locals(int argc, KrkValue argv[], int hasKw) { +KRK_FUNC(locals,{ + FUNCTION_TAKES_AT_MOST(1); KrkValue dict = krk_dict_of(0, NULL, 0); krk_push(dict); @@ -602,10 +604,10 @@ static KrkValue _locals(int argc, KrkValue argv[], int hasKw) { } return krk_pop(); -} +}) -static KrkValue _isinstance(int argc, KrkValue argv[], int hasKw) { - if (argc != 2) return krk_runtimeError(vm.exceptions->argumentError, "isinstance expects 2 arguments, got %d", argc); +KRK_FUNC(isinstance,{ + FUNCTION_TAKES_EXACTLY(2); if (IS_CLASS(argv[1])) { return BOOLEAN_VAL(krk_isInstanceOf(argv[0], AS_CLASS(argv[1]))); } else if (IS_TUPLE(argv[1])) { @@ -618,7 +620,7 @@ static KrkValue _isinstance(int argc, KrkValue argv[], int hasKw) { } else { return krk_runtimeError(vm.exceptions->typeError, "isinstance() arg 2 must be class or tuple"); } -} +}) static KrkValue _module_repr(int argc, KrkValue argv[], int hasKw) { KrkInstance * self = AS_INSTANCE(argv[0]); @@ -692,9 +694,10 @@ static KrkValue _strBase(int argc, KrkValue argv[], int hasKw) { return out; } -static KrkValue _type(int argc, KrkValue argv[], int hasKw) { +KRK_FUNC(type,{ + FUNCTION_TAKES_EXACTLY(1); return OBJECT_VAL(krk_getType(argv[0])); -} +}) KRK_FUNC(getattr,{ FUNCTION_TAKES_AT_LEAST(2); @@ -830,24 +833,23 @@ KRK_METHOD(property,__set__,{ return krk_runtimeError(vm.exceptions->attributeError, "attribute can not be set"); }) -static KrkValue _id(int argc, KrkValue argv[], int hasKw) { - if (argc != 1) return krk_runtimeError(vm.exceptions->argumentError, "expected exactly one argument"); +KRK_FUNC(id,{ + FUNCTION_TAKES_EXACTLY(1); if (!IS_OBJECT(argv[0])) return krk_runtimeError(vm.exceptions->typeError, "'%s' is a primitive type and has no identity", krk_typeName(argv[0])); return INTEGER_VAL((size_t)AS_OBJECT(argv[0])); -} +}) -static KrkValue _hash(int argc, KrkValue argv[], int hasKw) { - /* This is equivalent to the method version */ - if (argc != 1) return krk_runtimeError(vm.exceptions->argumentError, "expected exactly one argument"); +KRK_FUNC(hash,{ + FUNCTION_TAKES_EXACTLY(1); return INTEGER_VAL(krk_hashValue(argv[0])); -} +}) _noexport void _createAndBind_builtins(void) { vm.baseClasses->objectClass = krk_newClass(S("object"), NULL); krk_push(OBJECT_VAL(vm.baseClasses->objectClass)); - krk_defineNative(&vm.baseClasses->objectClass->methods, ":__class__", _type); + krk_defineNative(&vm.baseClasses->objectClass->methods, ":__class__", FUNC_NAME(krk,type)); krk_defineNative(&vm.baseClasses->objectClass->methods, ".__dir__", krk_dirObject); krk_defineNative(&vm.baseClasses->objectClass->methods, ".__str__", _strBase); krk_defineNative(&vm.baseClasses->objectClass->methods, ".__repr__", _strBase); /* Override if necesary */ @@ -958,36 +960,36 @@ void _createAndBind_builtins(void) { BIND_METHOD(enumerateobject,__repr__); krk_finalizeClass(enumerateobject); - BUILTIN_FUNCTION("isinstance", _isinstance, + BUILTIN_FUNCTION("isinstance", FUNC_NAME(krk,isinstance), "@brief Check if an object is an instance of a type.\n" "@arguments inst, cls\n\n" "Determine if an object @p inst is an instance of the given class @p cls or one if its subclasses. " "@p cls may be a single class or a tuple of classes."); - BUILTIN_FUNCTION("globals", _globals, + BUILTIN_FUNCTION("globals", FUNC_NAME(krk,globals), "@brief Update and a return a mapping of names in the global namespace.\n\n" "Produces a dict mapping all of the names of the current globals namespace to their values. " "Updating this dict has no meaning, but modifying mutable values within it can affect the global namespace."); - BUILTIN_FUNCTION("locals", _locals, + BUILTIN_FUNCTION("locals", FUNC_NAME(krk,locals), "@brief Update and return a mapping of names in the current local scope.\n" "@arguments callDepth=1\n\n" "Produces a dict mapping the names of the requested locals scope to their current stack values. " "If @p callDepth is provided, the locals of an outer call frame will be returned. If the requested " "call depth is out of range, an exception will be raised."); - BUILTIN_FUNCTION("dir", _dir, "Return a list of known property names for a given object."); - BUILTIN_FUNCTION("len", _len, "Return the length of a given sequence object."); - BUILTIN_FUNCTION("repr", _repr, "Produce a string representation of the given object."); + BUILTIN_FUNCTION("dir", FUNC_NAME(krk,dir), "Return a list of known property names for a given object."); + BUILTIN_FUNCTION("len", FUNC_NAME(krk,len), "Return the length of a given sequence object."); + BUILTIN_FUNCTION("repr", FUNC_NAME(krk,repr), "Produce a string representation of the given object."); BUILTIN_FUNCTION("print", _print, "@brief Print text to the standard output.\n" "@arguments *args,sep=' ',end='\\n'\n\n" "Prints the string representation of each argument to the standard output. " "The keyword argument @p sep specifies the string to print between values. " "The keyword argument @p end specifies the string to print after all of the values have been printed."); - BUILTIN_FUNCTION("ord", _ord, "Obtain the ordinal integer value of a codepoint or byte."); - BUILTIN_FUNCTION("chr", _chr, "Convert an integer codepoint to its string representation."); - BUILTIN_FUNCTION("hex", _hex, "Convert an integer value to a hexadecimal string."); - BUILTIN_FUNCTION("oct", _oct, "Convert an integer value to an octal string."); - BUILTIN_FUNCTION("any", _any, "Returns True if at least one element in the given iterable is truthy, False otherwise."); - BUILTIN_FUNCTION("all", _all, "Returns True if every element in the given iterable is truthy, False otherwise."); + BUILTIN_FUNCTION("ord", FUNC_NAME(krk,ord), "Obtain the ordinal integer value of a codepoint or byte."); + BUILTIN_FUNCTION("chr", FUNC_NAME(krk,chr), "Convert an integer codepoint to its string representation."); + BUILTIN_FUNCTION("hex", FUNC_NAME(krk,hex), "Convert an integer value to a hexadecimal string."); + BUILTIN_FUNCTION("oct", FUNC_NAME(krk,oct), "Convert an integer value to an octal string."); + BUILTIN_FUNCTION("any", FUNC_NAME(krk,any), "Returns True if at least one element in the given iterable is truthy, False otherwise."); + BUILTIN_FUNCTION("all", FUNC_NAME(krk,all), "Returns True if every element in the given iterable is truthy, False otherwise."); BUILTIN_FUNCTION("getattr", FUNC_NAME(krk,getattr), "@brief Perform attribute lookup on an object using a string.\n" "@arguments obj,attribute,[default]\n\n" @@ -1008,15 +1010,15 @@ void _createAndBind_builtins(void) { "or other type with its own attribute table, then the field will be updated. If " "@p obj is a type without an attribute table and no class property provides an " "overriding setter for @p attribute, an @ref AttributeError will be raised."); - BUILTIN_FUNCTION("sum", _sum, + BUILTIN_FUNCTION("sum", FUNC_NAME(krk,sum), "@brief add the elements of an iterable.\n" "@arguments iterable,start=0\n\n" "Continuously adds all of the elements from @p iterable to @p start and returns the result " "when @p iterable has been exhausted."); - BUILTIN_FUNCTION("min", _min, "Return the lowest value in an iterable or the passed arguments."); - BUILTIN_FUNCTION("max", _max, "Return the highest value in an iterable or the passed arguments."); - BUILTIN_FUNCTION("id", _id, "Returns the identity of an object."); - BUILTIN_FUNCTION("hash", _hash, "Returns the hash of a value, used for table indexing."); + BUILTIN_FUNCTION("min", FUNC_NAME(krk,min), "Return the lowest value in an iterable or the passed arguments."); + BUILTIN_FUNCTION("max", FUNC_NAME(krk,max), "Return the highest value in an iterable or the passed arguments."); + BUILTIN_FUNCTION("id", FUNC_NAME(krk,id), "Returns the identity of an object."); + BUILTIN_FUNCTION("hash", FUNC_NAME(krk,hash), "Returns the hash of a value, used for table indexing."); BUILTIN_FUNCTION("map", FUNC_NAME(krk,map), "Return an iterator that applies a function to a series of iterables"); BUILTIN_FUNCTION("filter", FUNC_NAME(krk,filter), "Return an iterator that returns only the items from an iterable for which the given function returns true."); BUILTIN_FUNCTION("enumerate", FUNC_NAME(krk,enumerate), "Return an iterator that produces a tuple with a count the iterated values of the passed iteratable."); diff --git a/src/compiler.c b/src/compiler.c index 4613474..b86459b 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -285,8 +285,14 @@ static void finishError(KrkToken * token) { parser.hadError = 1; } -#define error(...) do { if (parser.panicMode) break; krk_runtimeError(vm.exceptions->syntaxError, __VA_ARGS__); finishError(&parser.previous); } while (0) -#define errorAtCurrent(...) do { if (parser.panicMode) break; krk_runtimeError(vm.exceptions->syntaxError, __VA_ARGS__); finishError(&parser.current); } while (0) +#ifdef KRK_NO_DOCUMENTATION +# define raiseSyntaxError(token, ...) do { if (parser.panicMode) break; krk_runtimeError(vm.exceptions->syntaxError, "syntax error"); finishError(token); } while (0) +#else +# define raiseSyntaxError(token, ...) do { if (parser.panicMode) break; krk_runtimeError(vm.exceptions->syntaxError, __VA_ARGS__); finishError(token); } while (0) +#endif + +#define error(...) raiseSyntaxError(&parser.previous, __VA_ARGS__) +#define errorAtCurrent(...) raiseSyntaxError(&parser.current, __VA_ARGS__) static void advance() { parser.previous = parser.current; diff --git a/src/util.h b/src/util.h index c78c904..9c1f176 100644 --- a/src/util.h +++ b/src/util.h @@ -27,6 +27,9 @@ * * These macros are intended to be used together to define functions for a class. */ +#ifdef KRK_NO_DOCUMENTATION +# define _method_name(f) "func" +#else static inline const char * _method_name(const char * func) { const char * out = func; if (*out == '_') out++; @@ -34,6 +37,7 @@ static inline const char * _method_name(const char * func) { if (*out == '_') out++; return out; } +#endif #define ADD_BASE_CLASS(obj, name, baseClass) krk_makeClass(vm.builtins, &obj, name, baseClass) diff --git a/src/vm.c b/src/vm.c index 33306e1..5eb4abd 100644 --- a/src/vm.c +++ b/src/vm.c @@ -300,7 +300,7 @@ inline void krk_push(KrkValue value) { inline KrkValue krk_pop() { krk_currentThread.stackTop--; if (unlikely(krk_currentThread.stackTop < krk_currentThread.stack)) { - fprintf(stderr, "Fatal error: stack underflow detected in VM, issuing breakpoint.\n"); + fprintf(stderr, "Fatal error: stack underflow detected in VM.\n"); return NONE_VAL(); } return *krk_currentThread.stackTop; @@ -868,7 +868,7 @@ int krk_callValue(KrkValue callee, int argCount, int extra) { KrkBoundMethod * bound = AS_BOUND_METHOD(callee); krk_currentThread.stackTop[-argCount - 1] = bound->receiver; if (!bound->method) { - krk_runtimeError(vm.exceptions->argumentError, "Attempted to call a method binding with no attached callable (did you forget to return something from a method decorator?)"); + krk_runtimeError(vm.exceptions->argumentError, "???"); return 0; } return krk_callValue(OBJECT_VAL(bound->method), argCount + 1, 0); @@ -1332,7 +1332,7 @@ const char * krk_typeName(KrkValue value) { return krk_getType(value)->name->chars; } -static KrkValue tryBind(const char * name, KrkValue a, KrkValue b, const char * msg) { +static KrkValue tryBind(const char * name, KrkValue a, KrkValue b, const char * operator, const char * msg) { krk_push(b); krk_push(a); KrkClass * type = krk_getType(a); @@ -1347,7 +1347,7 @@ static KrkValue tryBind(const char * name, KrkValue a, KrkValue b, const char * value = krk_callSimple(krk_peek(1), 1, 1); } if (IS_KWARGS(value)) { - return krk_runtimeError(vm.exceptions->typeError, msg, krk_typeName(a), krk_typeName(b)); + return krk_runtimeError(vm.exceptions->typeError, msg, operator, krk_typeName(a), krk_typeName(b)); } else { return value; } @@ -1366,7 +1366,7 @@ static KrkValue tryBind(const char * name, KrkValue a, KrkValue b, const char * } else if (IS_FLOATING(b)) { \ if (IS_INTEGER(a)) return FLOATING_VAL((double)AS_INTEGER(a) operator AS_FLOATING(b)); \ } \ - return tryBind("__" #name "__", a, b, "unsupported operand types for " #operator ": '%s' and '%s'"); \ + return tryBind("__" #name "__", a, b, #operator, "unsupported operand types for %s: '%s' and '%s'"); \ } MAKE_BIN_OP(add,+) @@ -1376,7 +1376,7 @@ MAKE_BIN_OP(div,/) #define MAKE_UNOPTIMIZED_BIN_OP(name,operator) \ KrkValue krk_operator_ ## name (KrkValue a, KrkValue b) { \ - return tryBind("__" #name "__", a, b, "unsupported operand types for " #operator ": '%s' and '%s'"); \ + return tryBind("__" #name "__", a, b, #operator, "unsupported operand types for %s: '%s' and '%s'"); \ } MAKE_UNOPTIMIZED_BIN_OP(pow,**) @@ -1387,12 +1387,12 @@ MAKE_UNOPTIMIZED_BIN_OP(pow,**) KrkValue krk_operator_ ## name (KrkValue a, KrkValue b) { \ if (IS_BOOLEAN(a) && IS_BOOLEAN(b)) return BOOLEAN_VAL(AS_INTEGER(a) operator AS_INTEGER(b)); \ if (IS_INTEGER(a) && IS_INTEGER(b)) return INTEGER_VAL(AS_INTEGER(a) operator AS_INTEGER(b)); \ - return tryBind("__" #name "__", a, b, "unsupported operand types for " #operator ": '%s' and '%s'"); \ + return tryBind("__" #name "__", a, b, #operator, "unsupported operand types for %s: '%s' and '%s'"); \ } #define MAKE_BIT_OP(name,operator) \ KrkValue krk_operator_ ## name (KrkValue a, KrkValue b) { \ if (IS_INTEGER(a) && IS_INTEGER(b)) return INTEGER_VAL(AS_INTEGER(a) operator AS_INTEGER(b)); \ - return tryBind("__" #name "__", a, b, "unsupported operand types for " #operator ": '%s' and '%s'"); \ + return tryBind("__" #name "__", a, b, #operator, "unsupported operand types for %s: '%s' and '%s'"); \ } MAKE_BIT_OP_BOOL(or,|) @@ -1411,7 +1411,7 @@ MAKE_BIT_OP(mod,%) /* not a bit op, but doesn't work on floating point */ } else if (IS_FLOATING(b)) { \ if (IS_INTEGER(a)) return BOOLEAN_VAL(AS_INTEGER(a) operator AS_INTEGER(b)); \ } \ - return tryBind("__" #name "__", a, b, "'" #operator "' not supported between instances of '%s' and '%s'"); \ + return tryBind("__" #name "__", a, b, #operator, "unsupported operand types for %s: '%s' and '%s'"); \ } MAKE_COMPARATOR(lt, <)