menu_generator (library)
Usage and interface
- Library usage:
:- use_module(library(menu_generator)). - Exports:
- Predicates:
menu/1, menu/2, menu/3, menu/4, get_menu_flag/3, set_menu_flag/3, space/1, get_menu_configs/1, save_menu_config/1, remove_menu_config/1, restore_menu_config/1, show_menu_configs/0, show_menu_config/1, get_menu_options/2, get_menu_flags/1, restore_menu_flags_list/1, get_menu_flags/2, restore_menu_flags/2, generate_js_menu/1, eq/3, neq/3, uni_type/2, vmember/2. - Regular Types:
menu_flag_values/1. - Multifiles:
$is_persistent/2, persistent_dir/2, persistent_dir/4, menu_default/3, menu_opt/6, hook_menu_flag_values/3, hook_menu_check_flag_value/3, hook_menu_flag_help/3, hook_menu_default_option/3.
- Predicates:
- Imports:
- System library modules:
persdb/persdbrt, aggregates, write, messages, prompt, lists. - Packages:
prelude, nonpure, hiord, assertions, regtypes, argnames, persdb, persdb(persdb_decl), nortchecks.
- System library modules:
Documentation on exports
Usage:menu(M,Bool)
Like menu/4 with no selected options, taking the menu level from the term M (example: ana(1) is expert, ana is naive), and using Bool to decide whether print help message or not.
Usage:menu(M,Level,Bool,AlreadySelectedOpts)
Execute the menu X. Level specifies the menu level. Bool decides whether print the help message. AlreadySelectedOpts is a list with the selected options.
Usage:get_menu_flag(M,F,V)
Returns the value in V of the flag F in the menu (-branch) M.
- The following properties should hold at call time:
(term_typing:atom/1)M is currently instantiated to an atom.
(term_typing:atom/1)F is currently instantiated to an atom.
(term_typing:var/1)V is a free variable.
Usage:set_menu_flag(M,F,V)
Set the value V of the flag F in the menu (-branch) M.
- The following properties should hold at call time:
(term_typing:atom/1)M is currently instantiated to an atom.
(term_typing:atom/1)F is currently instantiated to an atom.
(term_typing:var/1)V is a free variable.
Usage:space(N)
prints N spaces.
- The following properties should hold at call time:
(basic_props:num/1)N is a number.
Usage:get_menu_configs(X)
Returns a list of atoms in X with the name of stored configurations.
- The following properties should hold at call time:
(term_typing:var/1)X is a free variable. - The following properties should hold upon exit:
(basic_props:list/2)X is a list of atoms.
Usage:save_menu_config(Name)
Save the current flags configuration under the Name key.
- The following properties should hold at call time:
(basic_props:atm/1)Name is an atom.
Usage:remove_menu_config(Name)
Remove the configuration stored with the Name key (the same provided in save_menu_config/1).
- The following properties should hold at call time:
(basic_props:atm/1)Name is an atom.
Usage:restore_menu_config(Name)
Restore the configuration saved with the Name key (the same provided in save_menu_config/1).
- The following properties should hold at call time:
(basic_props:atm/1)Name is an atom.
Usage:show_menu_config(C)
Show specific configuration values pointed by C key (the same provided in save_menu_config/1).
- The following properties should hold at call time:
(basic_props:atm/1)C is an atom.
Usage:get_menu_options(Flag,V)
Returns possilbe options in V by fail for the flag Flag.
- The following properties should hold at call time:
(term_typing:atom/1)F is currently instantiated to an atom.
Usage:get_menu_flags(L)
Return a list L of all current menu flags, composed by terms with the form (M,F,V), where M is the menu, F the flag, and V the value. This list can be used as argument of restore_flags_list/1
- The following properties should hold at call time:
(term_typing:var/1)L is a free variable. - The following properties should hold upon exit:
(basic_props:list/1)L is a list.
Usage:restore_menu_flags_list(L)
Restores menu flags. L is a list of tuple (M,F,V) where M is the menu, F is the flag, and V is the value of the flag F in the menu M.
- The following properties should hold at call time:
(basic_props:list/1)L is a list.
Usage:get_menu_flags(M,L)
Return a list L of the current menu M composed by terms with the form (F=V), F the flag, and V the value. This list can be used as argument of restore_menu_flags/2
- The following properties should hold at call time:
(basic_props:term/1)M is any term.
(term_typing:var/1)L is a free variable. - The following properties should hold upon exit:
(basic_props:list/1)L is a list.
Usage:restore_menu_flags(M,F)
Restore the flag of the menu M. F is a list of terms F=V, which indicate the flag (F) and the value (V). M is the target menu to which those flags "belong". Additionally, F can contains terms like changed_to_menu(NM) that will put NM as the new target menu.
- The following properties should hold at call time:
(term_typing:atom/1)M is currently instantiated to an atom.
(basic_props:list/1)F is a list.
The current model for the JS menu is an array of menuq (object in JS).
var assert_rtcheck = menus.length ; var v_assert_rtcheck ; menus[ menus.length ] = new menuq( "assert_rtcheck", "Perform Run-Time Checks", "none,pred,pp_assrt,pp_code", "none", '((v_menu_level == "expert") && (v_inter_all == "check_assertions"))' ) ;
A variable with the same name as the flag name is created with the value of the index of the menu in the array. Another variable with 'v_' (v = value) indicates the value (of the flag) choosed by the user in the combo-boxes that appear on the webpage (note you should not read this if you have not seen the webpage working). The object menuq holds several things: the flag name (to find out the index in the array in some JS functions), the title, the options (notice there is no space in the options, this is important!), default option and the guard.
All the problem here is to generate the (JS) guard, because the rest of information is the same as in menu_opt/6. What code does is to execute the guard in prolog, and obtain a list of the form [flag=value,flag2=value2...]. Aditionally an element of the list can be another list, which indicates that the join operator (&& or ||) is swaped. For example: [a=1,[b=2,c=3],d=4] will be translated in JS like ((a==1)&&((b==2)||(c==3))&&(d==4)).
Prolog Guards (the ones in menu_opt) have been rewritten in order to do not generate free variables, i.e., they are finite guards now. So calling them with a variable in its first argument, we get the list like the named in the previous paragraph.
% Unfortunately, the current CiaoPP menu does not have all information % itself to concatenate several menus, i.e., when asking which kind of % action the user desire, depending on the answer one path or another % one is taken. Who decide which path? 'auto_inteface' does. We do have % to take this into account, because generating the assertions of a % "subpath" will produce the activation of it without permision of the % father (the menu which launch it).
Also, we have to keep in mind that menu has several submenus (or branches) defined and ones connect with others. For example, the menu
all, 'Select Menu Level' # menu_level - naive. all, 'Select Action Group' # inter_all - analyze :: all_menu_branch. check(1), 'Perform Compile-Time Checks' # assert_ctcheck - on. ... ana , 'Select Aliasing-Mode Analysis' # modes - shfr <- true.
defines 3 menus: all, check(1), and ana. It usually happends that one menu invoques (connect or continue) with another menu (then it is a submenu or a branch). When generating the guards we have to add additional restrictions to the guards in order to make submenus do not appear in the incorrect moment. For example, check(1) menu will be only active if menu_level = expert and inter_all=check_assertions (more on this come later). How are several menus connected between each other? The process of connecting the menus is post-processing the selected flags (options) via post hook (the one defined after :: field). The post-processing hook only have to add the element ask_menu(Branch,Level) or ask_menu(Branch) to the selected flag list (the argument of the hook). So let us say that when calling all_menu_branch( X , Y ) we get:
?- all_menu_branch(A,B). A = [inter_all=optimize,menu_level=naive|_A], B = [ask_menu(opt,0),inter_all=optimize,menu_level=naive|_A] ? ; A = [inter_all=optimize,menu_level=expert|_A], B = [ask_menu(opt,1),inter_all=optimize,menu_level=expert|_A] ? ; A = [inter_all=analyze,menu_level=naive|_A], B = [ask_menu(ana,0),inter_all=analyze,menu_level=naive|_A] ? ; A = [inter_all=analyze,menu_level=expert|_A], B = [ask_menu(ana,1),inter_all=analyze,menu_level=expert|_A] ? ; A = [inter_all=check_assertions,menu_level=naive|_A], B = [ask_menu(check,0),inter_all=check_assertions,menu_level=naive|_A] ? ; A = [inter_all=check_assertions,menu_level=expert|_A], B = [ask_menu(check,1),inter_all=check_assertions,menu_level=expert|_A] ? ; A = [inter_all=check_certificate,menu_level=_B|_A], B = [inter_all=check_certificate,menu_level=_B|_A] ? ; A = [inter_all=optimize,_A,menu_level=naive|_B], B = [ask_menu(opt,0),inter_all=optimize,_A,menu_level=naive|_B] ?
Notice that the last option contains free variables in the list (not taking the tail into account). That is the indicator for us to stop searching for more solutions. Additionally, we can have more complex things like:
?- opt_menu_branch(A,B). A = [menu_level=naive,inter_optimize=_A|_B], B = [ask_menu(_A,0),menu_level=naive,inter_optimize=_A|_B] ? ; A = [menu_level=expert,inter_optimize=_A|_B], B = [ask_menu(_A,1),menu_level=expert,inter_optimize=_A|_B] ? ; A = [menu_level=naive,_B,inter_optimize=_A|_C], B = [ask_menu(_A,0),menu_level=naive,_B,inter_optimize=_A|_C] ?
In this situation, the menu that will be asked will depend on the value of the flag inter_optimize, so we will have to generate as many ask_menu as possible values the flag has. The predicate generate_menu_path/2 solves all this problem: for a given flag, it looks up to find out the guard composed by flags that will activate the flag. % This predicate also consider the problem of menu aliasing, % i.e., the option optimize in inter_ana menu launch opt menu, so % optimize is an alias for opt or vice-versa. For example, for the given flag ass_not_stat_eval, the path is: [v_menu_level=expert, v_inter_all=check_assertions], that means that menu_level flag has to have the value "expert" and the inter_all flag has to have the value "check_assertions" (note that menu_level and inter_all defines two menu branches). If we would execute only the precondition we would get: [v_assert_ctcheck=on].
There are % two one limitations imposed to the JS menu. % The menu level indicated by menu_level flag, is hirewired. The % other limitation is more serious. All flags values in the JS menu are mapped into one set of flags. In other words, changing a value of a shared flag by two menu branch will be reflected on the other branch. For example, changing type analysis in analyze menu branch, will modify the value of the same flag in check assertions branch.
The last point to name is about generated JS guards. This world is not fair, and sometimes happends things you just do not expect. Here is one of those things. When calling the Prolog guards with the list of current selected values, the cases that can occur are much less than when seeing all the possible combinations. Something like (a=true||a=1)&&(b=2), in Prolog guard execution (with instantiated things) will mean: the selected options are not nil, and a=1 and b=2, or in other words: (a==1)&&(b==2). But in JS, unfortunately means: b=2. Nowadays, this problem is solved by clean_imperative_guard/2 which tries to remove all stupid true conditions, but I am sure Murphy is listening to me now and he started to create an user to make the call clean_imperative_guard/2 generates wrong answer.
Usage:generate_js_menu(DoNotIncludeList)
Reads all multifile menu_opt/6 predicates and writes in default output a JavaScript Menu.
- The following properties should hold at call time:
(basic_props:list/1)DoNotIncludeList is a list.
Usage:eq(Type,A,B)
Type is the value returned by the 2nd arg of uni_type. A and B are whatever terms. This predicate success if they are equal (like A=B).
Usage:neq(Type,A,B)
Type is the value returned by the 2nd arg of uni_type. A and B are whatever terms. The semantic is similar to A == B.
Documentation on multifiles
The predicate is of type data.
The predicate is of type data.
The predicate is of type data.
(Trust) Usage 1:menu_default(Menu,Flag,DefaultValue)
Menu is a term that has to correspond with the 1st argument of Menu. Flag is the desired flag to have a default value. DefaultValue is the default value of Flag.
- The following properties should hold at call time:
(basic_props:term/1)Menu is any term.
(basic_props:atm/1)Flag is an atom.
(basic_props:atm/1)DefaultValue is an atom.
(Trust) Usage 2:menu_default(Menu,Flag,DefaultValue)
- The following properties hold upon exit:
(basic_props:atm/1)Menu is an atom.
(basic_props:atm/1)Flag is an atom.
(basic_props:atm/1)DefaultValue is an atom.
(Trust) Usage 3:menu_default(Menu,Flag,DefaultValue)
This call mode can be used to ask which flags and its values has a menu menu
- The following properties should hold at call time:
(basic_props:atm/1)Menu is an atom.
(term_typing:var/1)Flag is a free variable.
(term_typing:var/1)DefaultValue is a free variable.
(Trust) Usage 4:menu_default(Menu,Flag,DefaultValue)
This call mode can be used to ask which value have the flag Flag in the menu menu
- The following properties should hold at call time:
(basic_props:atm/1)Menu is an atom.
(basic_props:atm/1)Flag is an atom.
(term_typing:var/1)DefaultValue is a free variable.
Usage 1:menu_opt(Menu,Flag,Text,Guard,BeforePrinting,SelectedHook)
Menu is a term that specifies the menu name. It can be an atom or just a predicate of arity 1, where the 1st argument indicates the menu level (i.e., ana(1) is the level 1 of 'ana' menu). Flag is the flag that will be asked.
Text is the test that will be printed when asking the Flag.
Guard is a predicate of arity 1 that is invoked to see if the flag should be asked. The argument is the selected menu options till moment in the way: [flag1=value1, flag2=value2, ...].
BeforePrinting is a predicate of arity 0, that is invoked whenever the menu option has been selected the validator menu options chooser.
SelectedHook is a predicate of arity 2, that is invoked whenever the flag has been selected by the user. The 1st argument are the current selected values, including the current flag, and in the 2nd argument the possible modified list is expected.
In summary, if Guard holds, then BeforePrinting is executed (no action is taken whether it fails or not), and after the user has types the option SelectedHook is invoked.
- The following properties should hold at call time:
(basic_props:term/1)Menu is any term.
(basic_props:atm/1)Flag is an atom.
(basic_props:atm/1)Text is an atom.
(basic_props:callable/1)Guard is a term which represents a goal, i.e., an atom or a structure.
(basic_props:callable/1)BeforePrinting is a term which represents a goal, i.e., an atom or a structure.
(basic_props:callable/1)SelectedHook is a term which represents a goal, i.e., an atom or a structure.
(Trust) Usage 2:menu_opt(Menu,Flag,Text,Guard,BeforePrinting,SelectedHook)
- The following properties should hold at call time:
(basic_props:term/1)Menu is any term.
(basic_props:term/1)Flag is any term.
(basic_props:term/1)Text is any term.
(basic_props:term/1)Guard is any term.
(basic_props:term/1)BeforePrinting is any term.
(basic_props:term/1)SelectedHook is any term.
Usage:hook_menu_flag_values(Menu,Flag,Values)
It is a hook. It is invoked whenever a menu question is printed. Values is a term which specifies the possible values. If Values is alist(List) -atom list-, then menu will check if the typed value by user belongs to List. If Values is a term ask(T,Flag), the menu will invoke hook_menu_check_flag_value/3 hook to check if introduced value is valid.
- The following properties should hold at call time:
(term_typing:atom/1)Menu is currently instantiated to an atom.
(term_typing:atom/1)Flag is currently instantiated to an atom.
(term_typing:var/1)Values is a free variable. - The following properties should hold upon exit:
(menu_generator:menu_flag_values/1)Flag values
Usage:hook_menu_check_flag_value(M,F,V)
It is a hook. It is invoked whenever the menu needs to check whether the answer introduced for the menu M is correct. This happens when hook_menu_flag_values/3 returns in its second argument something different than alist(_).
Usage:hook_menu_flag_help(M,F,H)
It is a hook. It is invoked whenever the user ask for a help description, H, of the flag F in the menu M.
Usage:hook_menu_default_option(M,F,D)
It is a hook. It is invoked whenever the menu needs to offer a default option to the user in the menu M and it has not been neither introduced before nor specified by menu_default/3.
Known bugs and planned improvements
- Run-time checks have been reported not to work with this code. That means that either the assertions here, or the code that implements the run-time checks are erroneous.