/* dictop.c: Function operators for dictionary manipulation. */ #define _POSIX_SOURCE #include "x.tab.h" #include "operator.h" #include "execute.h" #include "data.h" #include "ident.h" #include "memory.h" void op_dict_keys(void) { Data *args; List *keys; if (!func_init_1(&args, DICT)) return; keys = dict_keys(args[0].u.dict); pop(1); push_list(keys); list_discard(keys); } void op_dict_add(void) { Data *args; if (!func_init_3(&args, DICT, 0, 0)) return; anticipate_assignment(); args[0].u.dict = dict_add(args[0].u.dict, &args[1], &args[2]); pop(2); } void op_dict_del(void) { Data *args; if (!func_init_2(&args, DICT, 0)) return; if (!dict_contains(args[0].u.dict, &args[1])) { throw(keynf_id, "Key (%D) is not in the dictionary.", &args[1]); } else { anticipate_assignment(); args[0].u.dict = dict_del(args[0].u.dict, &args[1]); pop(1); } } void op_dict_add_elem(void) { Data *args, oldval, d; Sublist *sublist; if (!func_init_3(&args, DICT, 0, 0)) return; if (dict_find(args[0].u.dict, &args[1], &oldval) == keynf_id) { oldval.type = LIST; sublist_set_to_full_list(&oldval.u.sublist, list_new(0)); } else if (oldval.type != LIST) { throw(type_id, "Value for %D (%D) is not a list.", &args[0], &oldval); data_discard(&oldval); return; } /* Anticipate assignment, and also temporarily replace the value for the * key args[1] with 0 to get rid of the dictionary's reference count on * the list. */ anticipate_assignment(); d.type = INTEGER; d.u.val = 0; args[0].u.dict = dict_add(args[0].u.dict, &args[1], &d); /* Add the element to the list. */ sublist = &oldval.u.sublist; sublist_truncate(sublist); sublist->list = list_add(sublist->list, &args[2]); sublist->span++; /* Replace the dictionary's value for args[1] with the updated list. */ args[0].u.dict = dict_add(args[0].u.dict, &args[1], &oldval); data_discard(&oldval); pop(2); } void op_dict_del_elem(void) { Data *args, *elem, oldval, d; Sublist *sublist; int pos; if (!func_init_3(&args, DICT, 0, 0)) return; if (dict_find(args[0].u.dict, &args[1], &oldval) == keynf_id) { throw(keynf_id, "Key (%D) is not in the dictionary.", &args[1]); return; } if (oldval.type != LIST) { throw(type_id, "Value for %D (%D) is not a list.", &args[1], &oldval); data_discard(&oldval); return; } sublist = &oldval.u.sublist; pos = sublist_search(sublist, &args[2]); if (pos == -1) { /* The key's not there; make no modifications. */ data_discard(&oldval); pop(2); return; } anticipate_assignment(); if (sublist->span == 1) { /* args[2] is the only element in the list; delete the key from the * dictionary. */ args[0].u.dict = dict_del(args[0].u.dict, &args[1]); data_discard(&oldval); pop(2); return; } /* Temporarily replace the dictionary's value for the key args[1] with 0 * to get rid of the dictionary's reference count the list. */ d.type = INTEGER; d.u.val = 0; args[0].u.dict = dict_add(args[0].u.dict, &args[1], &d); /* Remove the list element corresponding to args[2]. */ sublist_truncate(sublist); elem = &sublist->list->el[sublist->start + pos]; data_discard(elem); MEMMOVE(elem, elem + 1, sublist->span - 1 - pos); sublist->list->len--; sublist->span--; /* Reassign the key in the dictionary. */ args[0].u.dict = dict_add(args[0].u.dict, &args[1], &oldval); data_discard(&oldval); pop(2); } void op_dict_contains(void) { Data *args; int val; if (!func_init_2(&args, DICT, 0)) return; val = dict_contains(args[0].u.dict, &args[1]); pop(2); push_int(val); }