@@ -349,6 +349,15 @@ void cog_reverse_list_inplace(cog_object** list) {
349
349
* list = prev ;
350
350
}
351
351
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
+
352
361
cog_object * m_list_show_recursive () {
353
362
cog_object * obj = cog_pop ();
354
363
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) {
518
527
return _wraptab (_rem_helper (tab -> next , key , cog_hash (key )-> as_int ));
519
528
}
520
529
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
+
521
543
void _table_show_rec_helper (cog_object * tree , cog_object * alist , cog_object * stream , int64_t * counter , bool readably ) {
522
544
if (!tree ) return ;
523
545
_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) {
665
687
cog_object * res = cog_run_well_known (obj , meth );
666
688
if (res && cog_same_identifiers (res , COG_GLOBALS .not_impl_sym )) {
667
689
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 " );
669
691
COG_ITER_LIST (COG_GLOBALS .modules , modobj ) {
670
692
cog_module * mod = (cog_module * )modobj -> as_ptr ;
671
693
if (mod -> types == NULL ) continue ;
@@ -2376,7 +2398,7 @@ cog_modfunc fne_empty = {
2376
2398
"Return an empty list."
2377
2399
};
2378
2400
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 ")
2380
2402
#define _NUMBERBODY (op , either_float_type , both_ints_type , both_ints_cast ) \
2381
2403
COG_ENSURE_N_ITEMS(2); \
2382
2404
cog_object* a = cog_pop(); \
@@ -3115,6 +3137,63 @@ cog_object* fn_dot() {
3115
3137
}
3116
3138
cog_modfunc fne_dot = {"." , COG_FUNC , fn_dot , "Return the value for a key in a table." };
3117
3139
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
+
3118
3197
cog_obj_type cog_ot_continuation = {"Continuation" , cog_walk_both , NULL };
3119
3198
3120
3199
cog_object * cog_make_continuation () {
@@ -3257,12 +3336,16 @@ static cog_modfunc* builtin_modfunc_table[] = {
3257
3336
& fne_rest ,
3258
3337
& fne_push ,
3259
3338
& fne_is_empty ,
3339
+ & fne_length ,
3260
3340
// table functions
3261
3341
& fne_table ,
3262
3342
& fne_list_to_tab ,
3263
3343
& fne_insert ,
3264
3344
& fne_remove ,
3265
3345
& fne_dot ,
3346
+ & fne_has ,
3347
+ & fne_values ,
3348
+ & fne_keys ,
3266
3349
// string functions
3267
3350
& fne_append ,
3268
3351
& fne_substring ,
0 commit comments