Skip to content

Commit 2bfe157

Browse files
last few tables stuff
1 parent d8b818a commit 2bfe157

File tree

2 files changed

+92
-5
lines changed

2 files changed

+92
-5
lines changed

cogni.c

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,15 @@ void cog_reverse_list_inplace(cog_object** list) {
349349
*list = prev;
350350
}
351351

352+
int64_t cog_list_length(cog_object* list) {
353+
int64_t len = 0;
354+
while (list) {
355+
len++;
356+
list = list->next;
357+
}
358+
return len;
359+
}
360+
352361
cog_object* m_list_show_recursive() {
353362
cog_object* obj = cog_pop();
354363
bool readably = cog_expect_type_fatal(cog_pop(), &cog_ot_bool)->as_int;
@@ -518,6 +527,19 @@ cog_object* cog_table_remove(cog_object* tab, cog_object* key) {
518527
return _wraptab(_rem_helper(tab->next, key, cog_hash(key)->as_int));
519528
}
520529

530+
static cog_object* _reduce_helper(cog_object* tree, cog_object* (*func)(cog_object*, cog_object*), cog_object* accum) {
531+
if (!tree) return accum;
532+
accum = _reduce_helper(tree->TLEFT, func, accum);
533+
accum = func(tree, accum);
534+
accum = _reduce_helper(tree->TRIGHT, func, accum);
535+
return accum;
536+
}
537+
538+
cog_object* cog_table_reduce(cog_object* table, cog_object* (*func)(cog_object*, cog_object*), cog_object* accum) {
539+
assert(table && table->type == &cog_ot_table);
540+
return _reduce_helper(table->next, func, accum);
541+
}
542+
521543
void _table_show_rec_helper(cog_object* tree, cog_object* alist, cog_object* stream, int64_t* counter, bool readably) {
522544
if (!tree) return;
523545
_table_show_rec_helper(tree->TLEFT, alist, stream, counter, readably);
@@ -665,7 +687,7 @@ cog_object* cog_run_well_known_strict(cog_object* obj, const char* meth) {
665687
cog_object* res = cog_run_well_known(obj, meth);
666688
if (res && cog_same_identifiers(res, COG_GLOBALS.not_impl_sym)) {
667689
const char* method_name = meth;
668-
fprintf(stderr, "error: %s not implemented for %s\n", method_name, obj->type ? obj->type->name : "NULL");
690+
fprintf(stderr, "error: %s not implemented for %s\n", method_name, obj->type ? obj->type->name : "empty List");
669691
COG_ITER_LIST(COG_GLOBALS.modules, modobj) {
670692
cog_module* mod = (cog_module*)modobj->as_ptr;
671693
if (mod->types == NULL) continue;
@@ -2376,7 +2398,7 @@ cog_modfunc fne_empty = {
23762398
"Return an empty list."
23772399
};
23782400

2379-
#define GET_TYPENAME_STRING(obj) (obj && obj->type ? obj->type->name : "NULL")
2401+
#define GET_TYPENAME_STRING(obj) (obj && obj->type ? obj->type->name : "empty List")
23802402
#define _NUMBERBODY(op, either_float_type, both_ints_type, both_ints_cast) \
23812403
COG_ENSURE_N_ITEMS(2); \
23822404
cog_object* a = cog_pop(); \
@@ -3115,6 +3137,63 @@ cog_object* fn_dot() {
31153137
}
31163138
cog_modfunc fne_dot = {".", COG_FUNC, fn_dot, "Return the value for a key in a table."};
31173139

3140+
cog_object* fn_has() {
3141+
COG_ENSURE_N_ITEMS(2);
3142+
cog_object* key = cog_pop();
3143+
cog_object* table = cog_pop();
3144+
COG_ENSURE_TYPE(table, &cog_ot_table);
3145+
ENSURE_HASHABLE(key);
3146+
bool found;
3147+
cog_table_get(table, key, &found);
3148+
cog_push(cog_box_bool(found));
3149+
return NULL;
3150+
}
3151+
cog_modfunc fne_has = {"Has", COG_FUNC, fn_has, "Return true if the key is in the table."};
3152+
3153+
static cog_object* _get_values(cog_object* tab, cog_object* list) {
3154+
cog_push_to(&list, tab->TVAL);
3155+
return list;
3156+
}
3157+
3158+
static cog_object* _get_keys(cog_object* tab, cog_object* list) {
3159+
cog_push_to(&list, tab->TKEY);
3160+
return list;
3161+
}
3162+
3163+
cog_object* fn_values() {
3164+
COG_ENSURE_N_ITEMS(1);
3165+
cog_object* table = cog_pop();
3166+
COG_ENSURE_TYPE(table, &cog_ot_table);
3167+
cog_push(cog_table_reduce(table, _get_values, NULL));
3168+
return NULL;
3169+
}
3170+
cog_modfunc fne_values = {"Values", COG_FUNC, fn_values, "Return a list of all the values in the table."};
3171+
3172+
cog_object* fn_keys() {
3173+
COG_ENSURE_N_ITEMS(1);
3174+
cog_object* table = cog_pop();
3175+
COG_ENSURE_TYPE(table, &cog_ot_table);
3176+
cog_push(cog_table_reduce(table, _get_keys, NULL));
3177+
return NULL;
3178+
}
3179+
cog_modfunc fne_keys = {"Keys", COG_FUNC, fn_keys, "Return a list of all the keys in the table."};
3180+
3181+
static cog_object* _table_len(cog_object* _, cog_object* accum) {
3182+
return cog_box_int(accum->as_int + 1);
3183+
}
3184+
3185+
cog_object* fn_length() {
3186+
COG_ENSURE_N_ITEMS(1);
3187+
cog_object* x = cog_pop();
3188+
if (!x) cog_push(cog_box_int(0)); // empty list
3189+
else if (x->type == &cog_ot_list) cog_push(cog_box_int(cog_list_length(x)));
3190+
else if (x->type == &cog_ot_string) cog_push(cog_box_int(cog_strlen(x)));
3191+
else if (x->type == &cog_ot_table) cog_push(cog_table_reduce(x, _table_len, cog_box_int(0)));
3192+
else COG_RETURN_ERROR(cog_sprintf("%s object has no length: %O", GET_TYPENAME_STRING(x), x));
3193+
return NULL;
3194+
}
3195+
cog_modfunc fne_length = {"Length", COG_FUNC, fn_length, "Return the length of a list, string, or table."};
3196+
31183197
cog_obj_type cog_ot_continuation = {"Continuation", cog_walk_both, NULL};
31193198

31203199
cog_object* cog_make_continuation() {
@@ -3257,12 +3336,16 @@ static cog_modfunc* builtin_modfunc_table[] = {
32573336
&fne_rest,
32583337
&fne_push,
32593338
&fne_is_empty,
3339+
&fne_length,
32603340
// table functions
32613341
&fne_table,
32623342
&fne_list_to_tab,
32633343
&fne_insert,
32643344
&fne_remove,
32653345
&fne_dot,
3346+
&fne_has,
3347+
&fne_values,
3348+
&fne_keys,
32663349
// string functions
32673350
&fne_append,
32683351
&fne_substring,

cogni.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,8 @@ char cog_maybe_escape_char(char, bool*);
394394
cog_object* cog_list_splice(cog_object**, cog_object*);
395395
#define cog_strcat cog_list_splice
396396

397+
int64_t cog_list_length(cog_object*);
398+
397399
/**
398400
* Duplicates a list shallowly. The items in the list are not copied.
399401
* This also works for duplicating a string.
@@ -418,6 +420,8 @@ void cog_push_to(cog_object**, cog_object*);
418420
*/
419421
cog_object* cog_pop_from(cog_object** stack);
420422

423+
cog_object* cog_table_reduce(cog_object*, cog_object* (*f)(cog_object*, cog_object*), cog_object*);
424+
421425
/**
422426
* Dumps an object to a stream.
423427
*/
@@ -650,8 +654,8 @@ extern cog_obj_type cog_ot_continuation;
650654
#define COG_ENSURE_TYPE(obj, typeobj) \
651655
do { \
652656
if ((obj) == NULL || (obj)->type != typeobj) { \
653-
COG_RETURN_ERROR(cog_sprintf("Expected %s, but got %s", \
654-
(typeobj) ? (typeobj)->name : "NULL", (obj) && (obj)->type ? (obj)->type->name : "NULL")); \
657+
COG_RETURN_ERROR(cog_sprintf("Expected %s, but got %s: %O", \
658+
(typeobj) ? (typeobj)->name : "empty List", (obj) && (obj)->type ? (obj)->type->name : "empty List", (obj))); \
655659
} \
656660
} while (0)
657661

@@ -670,7 +674,7 @@ extern cog_obj_type cog_ot_continuation;
670674
#define COG_GET_NUMBER(obj, var) \
671675
do { \
672676
if ((obj) == NULL || ((obj)->type != &cog_ot_int && (obj)->type != &cog_ot_float)) { \
673-
COG_RETURN_ERROR(cog_sprintf("Expected a number, but got %s", (obj) ? (obj)->type->name : "NULL")); \
677+
COG_RETURN_ERROR(cog_sprintf("Expected a number, but got %s: %O", (obj) ? (obj)->type->name : "empty List", (obj))); \
674678
} \
675679
else var = (obj)->type == &cog_ot_float ? (obj)->as_float : (obj)->as_int; \
676680
} while (0)

0 commit comments

Comments
 (0)