/** * See Copyright Notice in picrin.h */ #include "picrin.h" #include "picrin/object.h" KHASH_DEFINE(dict, pic_sym *, pic_value, kh_ptr_hash_func, kh_ptr_hash_equal) struct pic_dict * pic_make_dict(pic_state *pic) { struct pic_dict *dict; dict = (struct pic_dict *)pic_obj_alloc(pic, sizeof(struct pic_dict), PIC_TYPE_DICT); kh_init(dict, &dict->hash); return dict; } pic_value pic_dict_ref(pic_state *pic, struct pic_dict *dict, pic_sym *key) { khash_t(dict) *h = &dict->hash; khiter_t it; it = kh_get(dict, h, key); if (it == kh_end(h)) { pic_errorf(pic, "element not found for a key: ~s", pic_obj_value(key)); } return kh_val(h, it); } void pic_dict_set(pic_state PIC_UNUSED(*pic), struct pic_dict *dict, pic_sym *key, pic_value val) { khash_t(dict) *h = &dict->hash; int ret; khiter_t it; it = kh_put(dict, h, key, &ret); kh_val(h, it) = val; } int pic_dict_size(pic_state PIC_UNUSED(*pic), struct pic_dict *dict) { return kh_size(&dict->hash); } bool pic_dict_has(pic_state PIC_UNUSED(*pic), struct pic_dict *dict, pic_sym *key) { return kh_get(dict, &dict->hash, key) != kh_end(&dict->hash); } void pic_dict_del(pic_state *pic, struct pic_dict *dict, pic_sym *key) { khash_t(dict) *h = &dict->hash; khiter_t it; it = kh_get(dict, h, key); if (it == kh_end(h)) { pic_errorf(pic, "no slot named ~s found in dictionary", pic_obj_value(key)); } kh_del(dict, h, it); } bool pic_dict_next(pic_state PIC_UNUSED(*pic), struct pic_dict *dict, int *iter, pic_sym **key, pic_value *val) { khash_t(dict) *h = &dict->hash; int it = *iter; for (it = *iter; it != kh_end(h); ++it) { if (kh_exist(h, it)) { if (key) *key = kh_key(h, it); if (val) *val = kh_val(h, it); *iter = ++it; return true; } } return false; } static pic_value pic_dict_make_dictionary(pic_state *pic) { struct pic_dict *dict; pic_get_args(pic, ""); dict = pic_make_dict(pic); return pic_obj_value(dict); } static pic_value pic_dict_dictionary(pic_state *pic) { struct pic_dict *dict; pic_value *argv; int argc, i; pic_get_args(pic, "*", &argc, &argv); dict = pic_make_dict(pic); for (i = 0; i < argc; i += 2) { pic_assert_type(pic, argv[i], sym); pic_dict_set(pic, dict, pic_sym_ptr(argv[i]), argv[i+1]); } return pic_obj_value(dict); } static pic_value pic_dict_dictionary_p(pic_state *pic) { pic_value obj; pic_get_args(pic, "o", &obj); return pic_bool_value(pic, pic_dict_p(pic, obj)); } static pic_value pic_dict_dictionary_ref(pic_state *pic) { struct pic_dict *dict; pic_sym *key; pic_get_args(pic, "dm", &dict, &key); if (! pic_dict_has(pic, dict, key)) { return pic_false_value(pic); } return pic_cons(pic, pic_obj_value(key), pic_dict_ref(pic, dict, key)); } static pic_value pic_dict_dictionary_set(pic_state *pic) { struct pic_dict *dict; pic_sym *key; pic_value val; pic_get_args(pic, "dmo", &dict, &key, &val); if (pic_undef_p(pic, val)) { if (pic_dict_has(pic, dict, key)) { pic_dict_del(pic, dict, key); } } else { pic_dict_set(pic, dict, key, val); } return pic_undef_value(pic); } static pic_value pic_dict_dictionary_size(pic_state *pic) { struct pic_dict *dict; pic_get_args(pic, "d", &dict); return pic_int_value(pic, pic_dict_size(pic, dict)); } static pic_value pic_dict_dictionary_map(pic_state *pic) { struct pic_proc *proc; struct pic_dict *dict; khiter_t it; khash_t(dict) *kh; pic_value ret = pic_nil_value(pic); pic_get_args(pic, "ld", &proc, &dict); kh = &dict->hash; for (it = kh_begin(kh); it != kh_end(kh); ++it) { if (kh_exist(kh, it)) { pic_push(pic, pic_call(pic, proc, 1, pic_obj_value(kh_key(kh, it))), ret); } } return pic_reverse(pic, ret); } static pic_value pic_dict_dictionary_for_each(pic_state *pic) { struct pic_proc *proc; struct pic_dict *dict; khiter_t it; khash_t(dict) *kh; pic_get_args(pic, "ld", &proc, &dict); kh = &dict->hash; for (it = kh_begin(kh); it != kh_end(kh); ++it) { if (kh_exist(kh, it)) { pic_call(pic, proc, 1, pic_obj_value(kh_key(kh, it))); } } return pic_undef_value(pic); } static pic_value pic_dict_dictionary_to_alist(pic_state *pic) { struct pic_dict *dict; pic_value val, alist = pic_nil_value(pic); pic_sym *sym; int it = 0; pic_get_args(pic, "d", &dict); while (pic_dict_next(pic, dict, &it, &sym, &val)) { pic_push(pic, pic_cons(pic, pic_obj_value(sym), val), alist); } return alist; } static pic_value pic_dict_alist_to_dictionary(pic_state *pic) { struct pic_dict *dict; pic_value alist, e, it; pic_get_args(pic, "o", &alist); dict = pic_make_dict(pic); pic_for_each (e, pic_reverse(pic, alist), it) { pic_assert_type(pic, pic_car(pic, e), sym); pic_dict_set(pic, dict, pic_sym_ptr(pic_car(pic, e)), pic_cdr(pic, e)); } return pic_obj_value(dict); } static pic_value pic_dict_dictionary_to_plist(pic_state *pic) { struct pic_dict *dict; pic_value val, plist = pic_nil_value(pic); pic_sym *sym; int it = 0; pic_get_args(pic, "d", &dict); while (pic_dict_next(pic, dict, &it, &sym, &val)) { pic_push(pic, val, plist); pic_push(pic, pic_obj_value(sym), plist); } return plist; } static pic_value pic_dict_plist_to_dictionary(pic_state *pic) { struct pic_dict *dict; pic_value plist, e; pic_get_args(pic, "o", &plist); dict = pic_make_dict(pic); for (e = pic_reverse(pic, plist); ! pic_nil_p(pic, e); e = pic_cddr(pic, e)) { pic_assert_type(pic, pic_cadr(pic, e), sym); pic_dict_set(pic, dict, pic_sym_ptr(pic_cadr(pic, e)), pic_car(pic, e)); } return pic_obj_value(dict); } void pic_init_dict(pic_state *pic) { pic_defun(pic, "make-dictionary", pic_dict_make_dictionary); pic_defun(pic, "dictionary?", pic_dict_dictionary_p); pic_defun(pic, "dictionary", pic_dict_dictionary); pic_defun(pic, "dictionary-ref", pic_dict_dictionary_ref); pic_defun(pic, "dictionary-set!", pic_dict_dictionary_set); pic_defun(pic, "dictionary-size", pic_dict_dictionary_size); pic_defun(pic, "dictionary-map", pic_dict_dictionary_map); pic_defun(pic, "dictionary-for-each", pic_dict_dictionary_for_each); pic_defun(pic, "dictionary->alist", pic_dict_dictionary_to_alist); pic_defun(pic, "alist->dictionary", pic_dict_alist_to_dictionary); pic_defun(pic, "dictionary->plist", pic_dict_dictionary_to_plist); pic_defun(pic, "plist->dictionary", pic_dict_plist_to_dictionary); }