Cleanups for docs, stripped builds

This commit is contained in:
K. Lange 2021-03-18 14:59:26 +09:00
parent 30ef65355c
commit baad0997fb
4 changed files with 110 additions and 98 deletions

View File

@ -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.");

View File

@ -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;

View File

@ -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)

View File

@ -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, <)