Besides the builtin set of events, the Mercury debugger also supports events defined by the user. The intention is that users can define one kind of event for each semantically important event in the program that isn’t captured by the standard builtin events, and can then generate those events at the appropriate point in the source code. Each event appears in the source code as a call prefixed by the keyword ‘event’, with each argument of the call giving the value of an event attribute.
Users can specify the set of user defined events that can appear in a program, and the names, types and order of the attributes of each kind of user defined event, by giving the name of an event set specification file to the compiler when compiling that program as the argument of the ‘event-set-file-name’ option. This file should contain a header giving the event set’s name, followed by a sequence of one or more event specifications, like this:
event set queens event nodiag_fail( test_failed: string, arg_b: int, arg_d: int, arg_list_len: int synthesized by list_len_func(sorted_list), sorted_list: list(int) synthesized by list_sort_func(arg_list), list_len_func: function, list_sort_func: function, arg_list: list(int) ) event safe_test( test_list: listint ) event noargs
The header consists of the keywords ‘event set’ and an identifier giving the event set name. Each event specification consists of the keyword ‘event’, the name of the event, and, if the event has any attributes, a parenthesized list of those attributes. Each attribute’s specification consists of a name, a colon and information about the attribute.
There are three kinds of attributes.
The result types of function attributes are given by the types of the synthesized attributes they compute. The argument types of function attributes (and the number of those arguments) are given by the types of the arguments they are applied to. Each function attribute must be used to compute at least one synthesized attribute, otherwise there would be no way to compute its type. If it is used to compute more than one synthesized attribute, the result and argument types must be consistent.
Each event goal in the program must use the name of one of the events defined here as the predicate name of the call, and the call’s arguments must match the types of that event’s non-synthesized attributes. Given that B and N are integers and L is a list of integers, these event goals are fine,
event nodiag_fail("N - B", B, N, list.length, list.sort, [N | L]), event safe_test([1, 2, 3])
but these goals
event nodiag_fail("N - B", B, N, list.sort, list.length, [N | L]), event nodiag_fail("N - B", B, list.length, N, list.sort, [N | L]), event safe_test(, ) event safe_test(42) event nonexistent_event(42)
will all generate errors.
The attributes of event calls are always input, and the event goal is always ‘det’.