/* // Full copyright information is available in the file ../doc/CREDITS */ #define NATIVE_MODULE "$dictionary" #include "cdc.h" NATIVE_METHOD(dict_values) { cList * list; INIT_1_ARG(DICT); list = dict_values(DICT1); CLEAN_RETURN_LIST(list); } NATIVE_METHOD(dict_keys) { cList * list; INIT_1_ARG(DICT); list = dict_keys(DICT1); CLEAN_RETURN_LIST(list); } /* ugh; what we do to keep from copying */ NATIVE_METHOD(dict_add) { cDict * dict; cData arg1, arg2; DEF_args; INIT_ARGC(ARG_COUNT, 3, "three"); INIT_ARG1(DICT); dict = dict_dup(DICT1); data_dup(&arg1, &args[1]); data_dup(&arg2, &args[2]); CLEAN_STACK(); anticipate_assignment(); dict = dict_add(dict, &arg1, &arg2); data_discard(&arg1); data_discard(&arg2); RETURN_DICT(dict); } NATIVE_METHOD(dict_del) { cData arg1; cDict * dict; DEF_args; INIT_ARGC(ARG_COUNT, 2, "two"); INIT_ARG1(DICT); if (!dict_contains(DICT1, &args[1])) THROW((keynf_id, "Key (%D) is not in the dictionary.", &args[1])); dict = dict_dup(DICT1); data_dup(&arg1, &args[1]); CLEAN_STACK(); anticipate_assignment(); dict = dict_del(dict, &arg1); data_discard(&arg1); RETURN_DICT(dict); } NATIVE_METHOD(dict_contains) { Int val; DEF_args; INIT_ARGC(ARG_COUNT, 2, "two"); INIT_ARG1(DICT); val = dict_contains(DICT1, &args[1]); CLEAN_RETURN_INTEGER(val); } NATIVE_METHOD(dict_add_elem) { cDict * dict; cData listd, d, key, value; DEF_args; INIT_ARGC(ARG_COUNT, 3, "three"); INIT_ARG1(DICT); if (dict_find(DICT1, &args[1], &listd) == keynf_id) { listd.type = LIST; listd.u.list = list_new(0); } else if (listd.type != LIST) { cthrow(type_id, "Value for %D (%D) is not a list.", &args[0], &listd); data_discard(&listd); RETURN_FALSE; } /* // set the list to zero to remove the reference to the list, then // dup the dictionary so we can clear the stack and anticipate the // assignmenent, all to keep references at their most minimal so we // do not copy if we do not need to. // // also dup the key and the value being inserted. */ d.type = INTEGER; d.u.val = 0; dict = dict_add(DICT1, &args[1], &d); dict = dict_dup(dict); data_dup(&key, &args[1]); data_dup(&value, &args[2]); /* clean the stack and anticipate the assignment */ CLEAN_STACK(); anticipate_assignment(); /* Add the element to the list. */ listd.u.list = list_add(listd.u.list, &value); dict = dict_add(dict, &key, &listd); data_discard(&key); data_discard(&value); data_discard(&listd); RETURN_DICT(dict); } NATIVE_METHOD(dict_del_elem) { cDict * dict; cData dlist, d, elem, key; cList * list; Int pos; DEF_args; INIT_ARGC(ARG_COUNT, 3, "three"); INIT_ARG1(DICT); if (dict_find(DICT1, &args[1], &dlist) == keynf_id) THROW((keynf_id, "Key (%D) is not in the dictionary.", &args[1])) else if (dlist.type != LIST) { cthrow(type_id, "Value for %D (%D) is not a list.", &args[0], &dlist); data_discard(&dlist); RETURN_FALSE; } dict = dict_dup(DICT1); data_dup(&key, &args[1]); data_dup(&elem, &args[2]); list = dlist.u.list; /* clean the stack and anticipate the assignment */ CLEAN_STACK(); anticipate_assignment(); /* find the element in the list */ pos = list_search(list, &elem); /* we are finished with 'elem' */ data_discard(&elem); /* the element is not in the list, simply return the dictionary */ if (pos == -1) { data_discard(&dlist); data_discard(&key); RETURN_DICT(dict); } /* if the list length is one, then simply delete the dict element */ if (list_length(list) == 1) { dict = dict_del(dict, &key); data_discard(&dlist); data_discard(&key); RETURN_DICT(dict); } /* // Temorarily set the dictionary's value for the key to zero, to // remove the reference to the list. */ d.type = INTEGER; d.u.val = 0; dict = dict_add(dict, &key, &d); /* Remove elem from the list */ dlist.u.list = list_delete(list, pos); /* Set the new list as the value for the key in the dictionary */ dict = dict_add(dict, &key, &dlist); /* clean up and return */ data_discard(&dlist); data_discard(&key); RETURN_DICT(dict); } NATIVE_METHOD(dict_union) { cDict * dict1, * dict2; INIT_2_ARGS(DICT, DICT) dict1 = dict_dup(DICT1); dict2 = dict_dup(DICT2); CLEAN_STACK(); anticipate_assignment(); RETURN_DICT(dict_union(dict1, dict2)); }