Expose basic operators and add more builtins, list functions

This commit is contained in:
K. Lange 2021-02-05 19:05:08 +09:00
parent 4d05ca218c
commit 930b599e82
8 changed files with 132 additions and 10 deletions

View File

@ -426,10 +426,6 @@ void _createAndBind_builtins(void) {
krk_finalizeClass(LicenseReader);
krk_attachNamedObject(&vm.builtins->fields, "license", (KrkObj*)krk_newInstance(LicenseReader));
BUILTIN_FUNCTION("listOf", krk_list_of, "Convert argument sequence to list object.");
BUILTIN_FUNCTION("dictOf", krk_dict_of, "Convert argument sequence to dict object.");
BUILTIN_FUNCTION("tupleOf",krk_tuple_of,"Convert argument sequence to tuple object.");
BUILTIN_FUNCTION("isinstance", _isinstance, "Determine if an object is an instance of the given class or one if its subclasses.");
BUILTIN_FUNCTION("globals", _globals, "Return a mapping of names in the current global namespace.");
BUILTIN_FUNCTION("dir", _dir, "Return a list of known property names for a given object.");

View File

@ -335,6 +335,8 @@ void _createAndBind_dictClass(void) {
krk_finalizeClass(dict);
dict->docstring = S("Mapping of arbitrary keys to values.");
BUILTIN_FUNCTION("dictOf", krk_dict_of, "Convert argument sequence to dict object.");
KrkClass * dictitems = ADD_BASE_CLASS(vm.baseClasses.dictitemsClass, "dictitems", vm.objectClass);
dictitems->allocSize = sizeof(struct DictItems);
dictitems->_ongcscan = _dictitems_gcscan;

View File

@ -8,6 +8,11 @@
if (index < 0) index += self->values.count; \
if (index < 0 || index >= (krk_integer_type)self->values.count) return krk_runtimeError(vm.exceptions.indexError, "list index out of range: " PRIkrk_int, index)
#define LIST_WRAP_SOFT(val) \
if (val < 0) val += self->values.count; \
if (val < 0) val = 0; \
if (val > (krk_integer_type)self->values.count) val = self->values.count
static void _list_gcscan(KrkInstance * self) {
for (size_t i = 0; i < ((KrkList*)self)->values.count; ++i) {
krk_markValue(((KrkList*)self)->values.values[i]);
@ -227,6 +232,95 @@ KRK_METHOD(list,pop,{
}
})
KRK_METHOD(list,remove,{
METHOD_TAKES_EXACTLY(1);
for (size_t i = 0; i < self->values.count; ++i) {
if (krk_valuesEqual(self->values.values[i], argv[1])) {
return FUNC_NAME(list,pop)(2,(KrkValue[]){argv[0], INTEGER_VAL(i)},0);
}
}
return krk_runtimeError(vm.exceptions.valueError, "not found");
})
KRK_METHOD(list,clear,{
METHOD_TAKES_NONE();
krk_freeValueArray(&self->values);
})
KRK_METHOD(list,index,{
METHOD_TAKES_AT_LEAST(1);
METHOD_TAKES_AT_MOST(3);
krk_integer_type min = 0;
krk_integer_type max = self->values.count;
if (argc > 2) {
if (IS_INTEGER(argv[2]))
min = AS_INTEGER(argv[2]);
else
return krk_runtimeError(vm.exceptions.typeError, "min must be int, not '%s'", krk_typeName(argv[2]));
}
if (argc > 3) {
if (IS_INTEGER(argv[3]))
max = AS_INTEGER(argv[3]);
else
return krk_runtimeError(vm.exceptions.typeError, "max must be int, not '%s'", krk_typeName(argv[3]));
}
LIST_WRAP_SOFT(min);
LIST_WRAP_SOFT(max);
for (krk_integer_type i = min; i < max; ++i) {
if (krk_valuesEqual(self->values.values[i], argv[1])) return INTEGER_VAL(i);
}
return krk_runtimeError(vm.exceptions.valueError, "not found");
})
KRK_METHOD(list,count,{
METHOD_TAKES_EXACTLY(1);
krk_integer_type count = 0;
for (size_t i = 0; i < self->values.count; ++i) {
if (krk_valuesEqual(self->values.values[i], argv[1])) count++;
}
return INTEGER_VAL(count);
})
KRK_METHOD(list,copy,{
METHOD_TAKES_NONE();
return krk_list_of(self->values.count, self->values.values);
})
KRK_METHOD(list,reverse,{
METHOD_TAKES_NONE();
for (size_t i = 0; i < (self->values.count) / 2; i++) {
KrkValue tmp = self->values.values[i];
self->values.values[i] = self->values.values[self->values.count-i-1];
self->values.values[self->values.count-i-1] = tmp;
}
return NONE_VAL();
})
static int _list_sorter(const void * _a, const void * _b) {
KrkValue a = *(KrkValue*)_a;
KrkValue b = *(KrkValue*)_b;
KrkValue ltComp = krk_operator_lt(a,b);
if (IS_NONE(ltComp) || (IS_BOOLEAN(ltComp) && AS_BOOLEAN(ltComp))) return -1;
KrkValue gtComp = krk_operator_gt(a,b);
if (IS_NONE(gtComp) || (IS_BOOLEAN(gtComp) && AS_BOOLEAN(gtComp))) return 1;
return 0;
}
KRK_METHOD(list,sort,{
METHOD_TAKES_NONE();
qsort(self->values.values, self->values.count, sizeof(KrkValue), _list_sorter);
})
FUNC_SIG(listiterator,__init__);
KRK_METHOD(list,__iter__,{
@ -280,6 +374,18 @@ _corrupt:
return krk_runtimeError(vm.exceptions.typeError, "Corrupt list iterator: %s", errorStr);
})
static KrkValue _sorted(int argc, KrkValue argv[], int hasKw) {
if (argc != 1) return krk_runtimeError(vm.exceptions.argumentError,"%s() takes %s %d argument%s (%d given)","sorted","exactly",1,argc);
KrkValue listOut = krk_list_of(0,NULL);
krk_push(listOut);
FUNC_NAME(list,extend)(2,(KrkValue[]){listOut,argv[0]},0);
if (!IS_NONE(vm.currentException)) return NONE_VAL();
FUNC_NAME(list,sort)(1,&listOut,0);
if (!IS_NONE(vm.currentException)) return NONE_VAL();
return krk_pop();
}
_noexport
void _createAndBind_listClass(void) {
KrkClass * list = ADD_BASE_CLASS(vm.baseClasses.listClass, "list", vm.objectClass);
@ -299,11 +405,21 @@ void _createAndBind_listClass(void) {
BIND_METHOD(list,extend);
BIND_METHOD(list,pop);
BIND_METHOD(list,insert);
BIND_METHOD(list,clear);
BIND_METHOD(list,index);
BIND_METHOD(list,count);
BIND_METHOD(list,copy);
BIND_METHOD(list,remove);
BIND_METHOD(list,reverse);
BIND_METHOD(list,sort);
krk_defineNative(&list->methods, ".__delitem__", FUNC_NAME(list,pop));
krk_defineNative(&list->methods, ".__str__", FUNC_NAME(list,__repr__));
krk_finalizeClass(list);
list->docstring = S("Mutable sequence of arbitrary values.");
BUILTIN_FUNCTION("listOf", krk_list_of, "Convert argument sequence to list object.");
BUILTIN_FUNCTION("sorted", _sorted, "Return a sorted representation of an iterable.");
KrkClass * listiterator = ADD_BASE_CLASS(vm.baseClasses.listiteratorClass, "listiterator", vm.objectClass);
BIND_METHOD(listiterator,__init__);
BIND_METHOD(listiterator,__call__);

View File

@ -446,6 +446,7 @@ KRK_METHOD(str,__lt__,{
if (!IS_STRING(argv[1])) {
return KWARGS_VAL(0); /* represents 'not implemented' */
}
if (AS_STRING(argv[0]) == AS_STRING(argv[1])) return BOOLEAN_VAL(0);
size_t aLen = AS_STRING(argv[0])->length;
size_t bLen = AS_STRING(argv[1])->length;
@ -465,6 +466,7 @@ KRK_METHOD(str,__gt__,{
if (!IS_STRING(argv[1])) {
return KWARGS_VAL(0); /* represents 'not implemented' */
}
if (AS_STRING(argv[0]) == AS_STRING(argv[1])) return BOOLEAN_VAL(0);
size_t aLen = AS_STRING(argv[0])->length;
size_t bLen = AS_STRING(argv[1])->length;

View File

@ -141,6 +141,8 @@ void _createAndBind_tupleClass(void) {
krk_defineNative(&vm.baseClasses.tupleClass->methods, ".__eq__", _tuple_eq);
krk_finalizeClass(vm.baseClasses.tupleClass);
BUILTIN_FUNCTION("tupleOf",krk_tuple_of,"Convert argument sequence to tuple object.");
ADD_BASE_CLASS(vm.baseClasses.tupleiteratorClass, "tupleiterator", vm.objectClass);
vm.baseClasses.tupleiteratorClass->allocSize = sizeof(struct TupleIter);
vm.baseClasses.tupleiteratorClass->_ongcscan = _tuple_iter_gcscan;

View File

@ -554,6 +554,7 @@ char * syn_krk_types[] = {
"list","dict","range", /* builtin classes */
"object","exception","isinstance","type","tuple",
"print","set","any","all","bool","ord","chr","hex",
"sorted","bytes",
NULL
};

View File

@ -1199,7 +1199,7 @@ static KrkValue tryBind(const char * name, KrkValue a, KrkValue b, const char *
*/
#define MAKE_BIN_OP(name,operator) \
static KrkValue operator_ ## name (KrkValue a, KrkValue b) { \
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)); \
if (IS_FLOATING(a)) { \
if (IS_INTEGER(b)) return FLOATING_VAL(AS_FLOATING(a) operator (double)AS_INTEGER(b)); \
@ -1216,7 +1216,7 @@ MAKE_BIN_OP(mul,*)
MAKE_BIN_OP(div,/)
#define MAKE_UNOPTIMIZED_BIN_OP(name,operator) \
static KrkValue operator_ ## name (KrkValue a, KrkValue b) { \
KrkValue krk_operator_ ## name (KrkValue a, KrkValue b) { \
return tryBind("__" #name "__", a, b, "unsupported operand types for " #operator ": '%s' and '%s'"); \
}
@ -1225,7 +1225,7 @@ MAKE_UNOPTIMIZED_BIN_OP(pow,**)
/* Bit ops are invalid on doubles in C, so we can't use the same set of macros for them;
* they should be invalid in Kuroko as well. */
#define MAKE_BIT_OP(name,operator) \
static KrkValue operator_ ## name (KrkValue a, KrkValue b) { \
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'"); \
}
@ -1238,7 +1238,7 @@ MAKE_BIT_OP(rshift,>>)
MAKE_BIT_OP(mod,%) /* not a bit op, but doesn't work on floating point */
#define MAKE_COMPARATOR(name, operator) \
static KrkValue operator_ ## name (KrkValue a, KrkValue b) { \
KrkValue krk_operator_ ## name (KrkValue a, KrkValue b) { \
if (IS_INTEGER(a) && IS_INTEGER(b)) return BOOLEAN_VAL(AS_INTEGER(a) operator AS_INTEGER(b)); \
if (IS_FLOATING(a)) { \
if (IS_INTEGER(b)) return BOOLEAN_VAL(AS_FLOATING(a) operator AS_INTEGER(b)); \
@ -1636,11 +1636,11 @@ static int valueDelProperty(KrkString * name) {
}
#define READ_BYTE() (*frame->ip++)
#define BINARY_OP(op) { KrkValue b = krk_pop(); KrkValue a = krk_pop(); krk_push(operator_ ## op (a,b)); break; }
#define BINARY_OP(op) { KrkValue b = krk_pop(); KrkValue a = krk_pop(); krk_push(krk_operator_ ## op (a,b)); break; }
#define BINARY_OP_CHECK_ZERO(op) { KrkValue b = krk_pop(); KrkValue a = krk_pop(); \
if ((IS_INTEGER(b) && AS_INTEGER(b) == 0)) { krk_runtimeError(vm.exceptions.zeroDivisionError, "integer division or modulo by zero"); goto _finishException; } \
else if ((IS_FLOATING(b) && AS_FLOATING(b) == 0.0)) { krk_runtimeError(vm.exceptions.zeroDivisionError, "float division by zero"); goto _finishException; } \
krk_push(operator_ ## op (a,b)); break; }
krk_push(krk_operator_ ## op (a,b)); break; }
#define READ_CONSTANT(s) (frame->closure->function->chunk.constants.values[readBytes(frame,s)])
#define READ_STRING(s) AS_STRING(READ_CONSTANT(s))

View File

@ -198,3 +198,6 @@ extern void _createAndBind_exceptions(void);
extern void _createAndBind_gcMod(void);
extern int krk_doRecursiveModuleLoad(KrkString * name);
extern KrkValue krk_operator_lt(KrkValue,KrkValue);
extern KrkValue krk_operator_gt(KrkValue,KrkValue);