% -----------------------------------------------------------------------------
%  (C) Altran Praxis Limited
% -----------------------------------------------------------------------------
% 
%  The SPARK toolset is free software; you can redistribute it and/or modify it
%  under terms of the GNU General Public License as published by the Free
%  Software Foundation; either version 3, or (at your option) any later
%  version. The SPARK toolset is distributed in the hope that it will be
%  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
%  Public License for more details. You should have received a copy of the GNU
%  General Public License distributed with the SPARK toolset; see file
%  COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy of
%  the license.
% 
% =============================================================================

%###############################################################################
% PURPOSE
%-------------------------------------------------------------------------------
% Configures system switches, taking into account the contents of the
% command line.
%###############################################################################

%###############################################################################
% MODULE
%###############################################################################

:- module(load__switches, [load_switches/0]).

%###############################################################################
% DEPENDENCIES
%###############################################################################

:- use_module('data__formats.pro',
              [add_type/2]).

:- use_module('data__switches.pro',
              [add_source_of_switch/2,
               add_switch_complexity_limit/1,
               add_switch_nocontradiction_hunt/1,
               add_switch_depth_limit/1,
               add_switch_verbose/1,
               add_switch_expression_reduction/1,
               add_switch_inference_limit/1,
               add_switch_input_file/1,
               get_switch_input_file/1,
               add_switch_log/1,
               add_switch_plain/1,
               add_switch_renum/1,
               add_switch_rule_substitution/1,
               add_switch_simplification/1,
               add_switch_standardisation/1,
               add_switch_substitution_elimination/1,
               add_switch_typecheck_only/1,
               add_switch_user_rules/1,
               add_switch_wrap/1,
               add_switch_help/1,
               add_switch_version/1,
               add_switch_empty/1,
               add_switch_usage/1,
               add_switch_hyp_limit/1,
               get_switch_hyp_limit/1,
               get_source_of_switch/2,
               get_switch_log/1,
               get_switch_deadpaths/1,
               add_switch_deadpaths/1,
               prune_source_of_switch/1,
               prune_switch_complexity_limit/0,
               prune_switch_nocontradiction_hunt/0,
               prune_switch_depth_limit/0,
               prune_switch_verbose/0,
               prune_switch_expression_reduction/0,
               prune_switch_inference_limit/0,
               prune_switch_log/0,
               prune_switch_plain/0,
               prune_switch_renum/0,
               prune_switch_rule_substitution/0,
               prune_switch_simplification/0,
               prune_switch_standardisation/0,
               prune_switch_substitution_elimination/0,
               prune_switch_typecheck_only/0,
               prune_switch_user_rules/0,
               prune_switch_help/0,
               prune_switch_version/0,
               prune_switch_empty/0,
               prune_switch_usage/0,
               prune_switch_wrap/0,
               prune_switch_deadpaths/0,
               prune_switch_hyp_limit/0]).

:- use_module('newutilities.pro',
              [contains_no_dups/1,
               flatten_list/2,
               generate_int_list/3,
               implode_separator_content_list/3]).

:- use_module('ioutilities.pro',
              [command_line_error/2,
               throw_error/2]).

:- use_module('parseutilities.pro',
              [parse_number/3,
               parse_atom/5,
               parse_atom_silent/4]).

:- use_module('data__system',
              [get_system_toolname/1]).

%###############################################################################
% TYPES
%###############################################################################

:- add_type('CMDLine',
            [empty,
             filename('InputFile_Atom'),
             simple_qualifier('SimpleQualifier'),
             log_qualifier('LogFile_Atom'),
             choices_qualifier('ChoicesName', 'SelectRange'),
             limit_qualifier('LimitName', 'Int'),
             usage_qualifier('UsageFile_Atom')]).

:- add_type('SimpleQualifier',
            [nolog,
             nowrap,
             verbose,
             nouserrules,
             plain,
             typecheck,
             norenum,
             help,
             version]).

:- add_type('ChoicesName',
            [nosimplification,
             nostandardisation,
             norule_substitution,
             nocontradiction_hunt,
             nosubstitution_elimination,
             noexpression_reduction]).

:- add_type('SelectRange',
            [all,
             none,
             specific('Range_List')]).

:- add_type('Range',
            [value('Int'),
             range('Lower_Int', 'Upper_Int')]).

:- add_type('LimitName',
            [complexity_limit,
             depth_limit,
             inference_limit]).

:- add_type('ProofFileKind',
            [verification_conditions,
             path_functions]).

%###############################################################################
% DATA
%###############################################################################

default_switch_hyp_limit(0).

%###############################################################################
% PREDICATES
%###############################################################################


:- set_prolog_flag(double_quotes, chars).

%===============================================================================
% load_switches.
%-------------------------------------------------------------------------------
% Establish the value of all switches, taking into account the contents of
% the command line.
%===============================================================================
load_switches:-
    % Establish automatic settings.
    set_auto_settings,

    % Retrieve arguments.
    current_prolog_flag(argv, Arguments_AtomList),

    % Parse arguments.
    parse_arguments(Arguments_AtomList, CMDLine_List),

    % Process parsed arguments.
    process_arguments(CMDLine_List),
    !.







%===============================================================================
% set_auto_settings.
%-------------------------------------------------------------------------------
% Initialise all switches to their default values.
%===============================================================================

set_auto_settings :-
    add_source_of_switch(switch_input_file, auto_set),

    add_switch_empty(off),
    add_source_of_switch(switch_empty, auto_set),

    add_switch_log(yes_log_file),
    add_source_of_switch(switch_log, auto_set),

    add_switch_wrap(on),
    add_source_of_switch(switch_wrap, auto_set),

    add_switch_verbose(off),
    add_source_of_switch(switch_verbose, auto_set),

    set_user_rules_switch,
    add_source_of_switch(switch_user_rules, auto_set),

    add_switch_plain(off),
    add_source_of_switch(switch_plain, auto_set),

    add_switch_typecheck_only(off),
    add_source_of_switch(switch_typecheck_only, auto_set),

    add_switch_renum(on),
    add_source_of_switch(switch_renum, auto_set),

    add_switch_simplification(all),
    add_source_of_switch(switch_simplification, auto_set),

    add_switch_standardisation(all),
    add_source_of_switch(switch_standardisation, auto_set),

    add_switch_rule_substitution(all),
    add_source_of_switch(switch_rule_substitution, auto_set),

    add_switch_nocontradiction_hunt(none),
    add_source_of_switch(switch_nocontradiction_hunt, auto_set),

    add_switch_substitution_elimination(all),
    add_source_of_switch(switch_substitution_elimination, auto_set),

    add_switch_expression_reduction(all),
    add_source_of_switch(switch_expression_reduction, auto_set),

    add_switch_complexity_limit(20),
    add_source_of_switch(switch_complexity_limit, auto_set),

    add_switch_depth_limit(5),
    add_source_of_switch(switch_depth_limit, auto_set),

    add_switch_inference_limit(40),
    add_source_of_switch(switch_inference_limit, auto_set),

    add_switch_help(off),
    add_source_of_switch(switch_help, auto_set),

    add_switch_version(off),
    add_source_of_switch(switch_version, auto_set),

    add_switch_usage(no_usage_file),
    add_source_of_switch(switch_usage, auto_set),

    set_deadpath_switch,
    add_source_of_switch(switch_deadpaths, auto_set),

    default_switch_hyp_limit(Hyp_Limit_Default),
    add_switch_hyp_limit(Hyp_Limit_Default),
    add_source_of_switch(switch_hyp_limit, auto_set),
    !.

%===============================================================================
% set_user_rules_switch.
%-------------------------------------------------------------------------------
% Only permit the use of user rules for the Simplifier.
%===============================================================================

set_user_rules_switch:-
    get_system_toolname('Simplifier'),
    !,
    add_switch_user_rules(on).

set_user_rules_switch:-
    get_system_toolname('ZombieScope'),
    !,
    add_switch_user_rules(off).

%===============================================================================
% set_deadpath_switch.
%-------------------------------------------------------------------------------
% Set the deadpath switch based on the toolname
%===============================================================================

set_deadpath_switch:-
    get_system_toolname('Simplifier'),
    !,
    add_switch_deadpaths(off).
    
set_deadpath_switch:-
    get_system_toolname('ZombieScope'),
    !,
    add_switch_deadpaths(on).
    

%===============================================================================
% parse_arguments(+Arguments_AtomList, -CMDLine_List).
%-------------------------------------------------------------------------------
% Parses the command line into an easily inspected structure. This is only
% concerned with the syntax. Syntactically correct arguments may be
% semantically wrong.
%===============================================================================

% The empty qualifier is detected when no other qualifiers are detected.
parse_arguments([], [empty]).

parse_arguments(Arguments_AtomList, CMDLine_List):-
    parse_arguments_x(Arguments_AtomList, CMDLine_List),
    !.

%-------------------------------------------------------------------------------

% Make the parse_legal_base_name call visible to the spxref tool.
:- public parse_simplifier_qualifier_part/3.
:- public parse_zombiescope_qualifier_part/3.

% From above, some qualifiers detected.
parse_arguments_x([], []).

% More arguments to consider.

% Process Simplifier arguments
parse_arguments_x([H_Arguments_Atom | T_Arguments_AtomList],
                  [H_CMDLine | T_CMDLine_List]):-
    get_switch_deadpaths(off),
    % Parse the qualifier.
    atom_chars(H_Arguments_Atom, H_Arguments_CharList),
    phrase(parse_simplifier_qualifier_part(H_CMDLine), H_Arguments_CharList),
    parse_arguments_x(T_Arguments_AtomList, T_CMDLine_List).

% Process ZombieScope arguments
parse_arguments_x([H_Arguments_Atom | T_Arguments_AtomList],
                  [H_CMDLine | T_CMDLine_List]):-
    get_switch_deadpaths(on),
    % Parse the qualifier.
    atom_chars(H_Arguments_Atom, H_Arguments_CharList),
    phrase(parse_zombiescope_qualifier_part(H_CMDLine), H_Arguments_CharList),
    parse_arguments_x(T_Arguments_AtomList, T_CMDLine_List).

% Failure to achieve the above is an error.
parse_arguments_x([H_Arguments_Atom | _T_Arguments_AtomList],
                  _CMDLine_List):-
    throw_error('Error in analysing command argument: ~a', [H_Arguments_Atom]).

%-------------------------------------------------------------------------------
% Processing of Simplifier flags.
%-------------------------------------------------------------------------------

parse_simplifier_qualifier_part(CMDLine) -->
    parse_simplifier_simple_qualifier(CMDLine),
    !.

parse_simplifier_qualifier_part(CMDLine) -->
    parse_simplifier_log_qualifier(CMDLine),
    !.

parse_simplifier_qualifier_part(CMDLine) -->
    parse_simplifier_usage_qualifier(CMDLine),
    !.

parse_simplifier_qualifier_part(CMDLine) -->
    parse_simplifier_choices_qualifier(CMDLine),
    !.

parse_simplifier_qualifier_part(CMDLine) -->
    parse_simplifier_limit_qualifier(CMDLine),
    !.

parse_simplifier_qualifier_part(CMDLine) -->
    parse_file_name(CMDLine),
    !.

%-------------------------------------------------------------------------------

parse_simplifier_simple_qualifier(simple_qualifier(SimpleQualifier)) -->
    parse_qualifier_prefix,
    parse_simplifier_simple_name(SimpleQualifier),
    !.

parse_simplifier_simple_name(help) -->
    parse_mandatory_and_optional("h", "elp"),
    !.

parse_simplifier_simple_name(nolog) -->
    parse_mandatory_and_optional("nol", "og"),
    !.

parse_simplifier_simple_name(nowrap) -->
    parse_mandatory_and_optional("now", "rap"),
    !.

parse_simplifier_simple_name(verbose) -->
    parse_mandatory_and_optional("verb", "ose"),
    !.

parse_simplifier_simple_name(nouserrules) -->
    parse_mandatory_and_optional("nou", "serrules"),
    !.

parse_simplifier_simple_name(plain) -->
    parse_mandatory_and_optional("p", "lain"),
    !.

parse_simplifier_simple_name(typecheck) -->
    parse_mandatory_and_optional("t", "ypecheck"),
    !.

parse_simplifier_simple_name(norenum) -->
    parse_mandatory_and_optional("nore", "num"),
    !.

parse_simplifier_simple_name(version) -->
    parse_mandatory_and_optional("vers", "ion"),
    !.
%-------------------------------------------------------------------------------
parse_simplifier_log_qualifier(log_qualifier(LogFile_Atom)) -->
    parse_qualifier_prefix,
    parse_mandatory_and_optional("l", "og"),
    "=",
    parse_atom([alpha_numeric, under_score, period], oneormore, LogFile_Atom),
    !.

%-------------------------------------------------------------------------------
parse_simplifier_usage_qualifier(usage_qualifier(UsageFile_Atom)) -->
    parse_qualifier_prefix,
    parse_mandatory_and_optional("us", "age"),
    "=",
    parse_atom([alpha_numeric, under_score, period], oneormore, UsageFile_Atom),
    !.

%-------------------------------------------------------------------------------

parse_simplifier_choices_qualifier(choices_qualifier(ChoicesName, SelectRange)) -->
    parse_qualifier_prefix,
    parse_simplifier_choices_name(ChoicesName),
    parse_chosen_units(SelectRange),
    !.
%-------------------------------------------------------------------------------
parse_simplifier_choices_name(nosimplification) -->
    parse_mandatory_and_optional("nosi", "mplification"),
    !.

parse_simplifier_choices_name(nostandardisation) -->
    parse_mandatory_and_optional("nost", "andardisation"),
    !.

parse_simplifier_choices_name(norule_substitution) -->
    parse_mandatory_and_optional("noru", "le_substitution"),
    !.

parse_simplifier_choices_name(nocontradiction_hunt) -->
    parse_mandatory_and_optional("noc", "ontradiction_hunt"),
    !.

parse_simplifier_choices_name(nosubstitution_elimination) -->
    parse_mandatory_and_optional("nosu", "bstitution_elimination"),
    !.

parse_simplifier_choices_name(noexpression_reduction) -->
    parse_mandatory_and_optional("noe", "xpression_reduction"),
    !.
%-------------------------------------------------------------------------------
parse_simplifier_limit_qualifier(limit_qualifier(LimitName, Int)) -->
    parse_qualifier_prefix,
    parse_simplifier_limit_name(LimitName),
    "=",
    parse_number(Int),
    !.
%-------------------------------------------------------------------------------
parse_simplifier_limit_name(complexity_limit) -->
    parse_mandatory_and_optional("c", "omplexity_limit"),
    !.

parse_simplifier_limit_name(depth_limit) -->
    parse_mandatory_and_optional("d", "epth_limit"),
    !.

parse_simplifier_limit_name(inference_limit) -->
    parse_mandatory_and_optional("i", "nference_limit"),
    !.

%-------------------------------------------------------------------------------
% Processing of ZombieScope flags.
%-------------------------------------------------------------------------------
parse_zombiescope_qualifier_part(CMDLine) -->
    parse_zombiescope_simple_qualifier(CMDLine),
    !.

parse_zombiescope_qualifier_part(CMDLine) -->
    parse_zombiescope_log_qualifier(CMDLine),
    !.

parse_zombiescope_qualifier_part(CMDLine) -->
    parse_zombiescope_limit_qualifier(CMDLine),
    !.

parse_zombiescope_qualifier_part(CMDLine) -->
    parse_file_name(CMDLine),
    !.
%-------------------------------------------------------------------------------
parse_zombiescope_simple_qualifier(simple_qualifier(SimpleQualifier)) -->
    parse_qualifier_prefix,
    parse_zombiescope_simple_name(SimpleQualifier),
    !.

parse_zombiescope_simple_name(help) -->
    parse_mandatory_and_optional("he", "lp"),
    !.

parse_zombiescope_simple_name(nolog) -->
    parse_mandatory_and_optional("nol", "og"),
    !.

parse_zombiescope_simple_name(nowrap) -->
    parse_mandatory_and_optional("now", "rap"),
    !.

parse_zombiescope_simple_name(plain) -->
    parse_mandatory_and_optional("p", "lain"),
    !.

parse_zombiescope_simple_name(norenum) -->
    parse_mandatory_and_optional("nor", "enum"),
    !.

parse_zombiescope_simple_name(version) -->
    parse_mandatory_and_optional("v", "ersion"),
    !.
%-------------------------------------------------------------------------------
parse_zombiescope_log_qualifier(log_qualifier(LogFile_Atom)) -->
    parse_qualifier_prefix,
    parse_mandatory_and_optional("l", "og"),
    "=",
    parse_atom([alpha_numeric, under_score, period], oneormore, LogFile_Atom),
    !.
%-------------------------------------------------------------------------------
parse_zombiescope_limit_qualifier(limit_qualifier(LimitName, Int)) -->
    parse_qualifier_prefix,
    parse_zombiescope_limit_name(LimitName),
    "=",
    parse_number(Int),
    !.
%-------------------------------------------------------------------------------
parse_zombiescope_limit_name(hyp_limit) -->
    parse_mandatory_and_optional("hy", "p_limit"),
    !.

%-------------------------------------------------------------------------------

% Constraint is imposed.
parse_chosen_units(specific(Range_List)) -->
    "=",
    parse_content_chosen_units(Range_List),
    !.

% No constraint imposed, so applies to all VCs.
parse_chosen_units(all) -->
    !.

%-------------------------------------------------------------------------------

% Non bracketed form for single ranges is acceptable.
parse_content_chosen_units([Range]) -->
    parse_range(Range),
    !.

% Otherwise brackets are required.
parse_content_chosen_units(Range_List) -->
    "(",
    parse_range_collection(Range_List),
    ")",
    !.

%-------------------------------------------------------------------------------

% First range is mandatory.
parse_range_collection([H_Range | T_Range_List]) -->
    parse_range(H_Range),
    parse_range_collection_x(T_Range_List),
    !.

% Additional ranges.
parse_range_collection_x([H_Range | T_Range_List]) -->
    ",",
    parse_range(H_Range),
    parse_range_collection_x(T_Range_List),
    !.

% No more.
parse_range_collection_x([]) -->
    !.

%-------------------------------------------------------------------------------

parse_range(range(Lower_Int, Upper_Int)) -->
    parse_number(Lower_Int),
    "-",
    parse_number(Upper_Int),
    !.

parse_range(value(Int)) -->
    parse_number(Int),
    !.

%-------------------------------------------------------------------------------


%-------------------------------------------------------------------------------

% File name is a sequence of alpha numeric characters, '_' and '.'. Note
% that '/' and '\' are accepted, to specify files outside the current
% directory on both unix and windows. Further, note that ':' is accepted to
% allow for windows rooted drive names. Significantly, the file name does
% not contain white space.
parse_file_name(filename(InputFile_Atom)) -->
    parse_atom([alpha_numeric, under_score, hyphen, period, forwardslash,
                backwardslash, colon], oneormore, InputFile_Atom),
    !.

%-------------------------------------------------------------------------------

parse_mandatory_and_optional(Mandatory_CharList, Optional_CharList) -->
    Mandatory_CharList,
    parse_optional(Optional_CharList),
    !.

%-------------------------------------------------------------------------------

parse_optional([H_Char | T_CharList]) -->
    [H_Char],
    parse_optional(T_CharList).

parse_optional(_T_CharList) -->
    "".

%-------------------------------------------------------------------------------

% SEPR:2369: Should the simplifier support Unix style switches (-switch)?
% If so, should the interface to be simplifier be platform dependent, or
% should both switch styles be allowed?
parse_qualifier_prefix -->
    {qualifier_prefix(Char)},
    [Char],
    !.

%===============================================================================
% qualifier_prefix(+Char).
%-------------------------------------------------------------------------------
% The legal qualifier prefixes.
%===============================================================================

qualifier_prefix('/').
qualifier_prefix('-').

%===============================================================================
% process_arguments(+CMDLine_List).
%-------------------------------------------------------------------------------
% Processes the parsed arguments.
%===============================================================================

process_arguments([]):-
    !.

process_arguments([H_CMDLine | T_CMDLine_List]):-
    process_argument(H_CMDLine),
    process_arguments(T_CMDLine_List).

%-------------------------------------------------------------------------------

% empty
%------

process_argument(empty):-
    get_source_of_switch(switch_empty, auto_set),
    prune_source_of_switch(switch_empty),
    add_switch_empty(on),
    add_source_of_switch(switch_empty, user_set),
    !.

process_argument(empty):-
    get_source_of_switch(switch_input_file, user_set),
    command_line_error('Unexpected multiple instances of empty command-line detected.\n', []).

% filename
%---------

process_argument(filename(InputFile_Atom)):-
    get_source_of_switch(switch_input_file, auto_set),
    prune_source_of_switch(switch_input_file),
    add_switch_input_file(InputFile_Atom),
    add_source_of_switch(switch_input_file, user_set),
    !.

process_argument(filename(SecondInputFile_Atom)):-
    get_source_of_switch(switch_input_file, user_set),
    get_switch_input_file(InputFile_Atom),
    command_line_error('Multiple file names specified on the command-line (~a and ~a)\n',
                       [InputFile_Atom,
                        SecondInputFile_Atom]).

% log
%----

% First occurrence of a log switch (here /nolog).
process_argument(simple_qualifier(nolog)):-
    get_source_of_switch(switch_log, auto_set),
    prune_switch_log,
    prune_source_of_switch(switch_log),
    add_switch_log(no_log_file),
    add_source_of_switch(switch_log, user_set),
    !.

% First occurrence of a log switch (here /log=...).
process_argument(log_qualifier(LogFile_Atom)):-
    get_source_of_switch(switch_log, auto_set),
    prune_switch_log,
    prune_source_of_switch(switch_log),
    add_switch_log(provided_log_file(LogFile_Atom)),
    add_source_of_switch(switch_log, user_set),
    !.

% Duplicate occurrence of a log switch (order: /nolog /nolog).
process_argument(simple_qualifier(nolog)):-
    get_source_of_switch(switch_log, user_set),
    get_switch_log(no_log_file),
    command_line_error('Illegal multiple uses of /nolog qualifier\n', []).

% Duplicate occurrence of a log switch (order: /nolog /log=...).
process_argument(simple_qualifier(nolog)):-
    get_source_of_switch(switch_log, user_set),
    get_switch_log(provided_log_file(_File_Atom)),
    command_line_error('Inconsistent use of /log=... and -nolog qualifiers\n', []).

% Duplicate occurrence of a log switch (order: -log=... -nolog).
process_argument(log_qualifier(_LogFile_Atom)):-
    get_source_of_switch(switch_log, user_set),
    get_switch_log(no_log_file),
    command_line_error('Inconsistent use of -log=... and -nolog qualifiers\n', []).

% Duplicate occurrence of a log switch (order: -log=... -log=...).
process_argument(log_qualifier(_OneLogFile_Atom)):-
    get_source_of_switch(switch_log, user_set),
    get_switch_log(provided_log_file(_TwoLogFile_Atom)),
    command_line_error('Illegal multiple uses of -log=... qualifier\n', []).

% wrap
%-----

process_argument(simple_qualifier(nowrap)):-
    get_source_of_switch(switch_wrap, auto_set),
    prune_switch_wrap,
    prune_source_of_switch(switch_wrap),
    add_switch_wrap(off),
    add_source_of_switch(switch_wrap, user_set),
    !.

process_argument(simple_qualifier(nowrap)):-
    get_source_of_switch(switch_wrap, user_set),
    command_line_error('-nowrap qualifier appears more than once on command-line\n', []).

% verbose
%--------

process_argument(simple_qualifier(verbose)):-
    get_source_of_switch(switch_verbose, auto_set),
    prune_switch_verbose,
    prune_source_of_switch(switch_verbose),
    add_switch_verbose(on),
    add_source_of_switch(switch_verbose, user_set),
    !.

process_argument(simple_qualifier(verbose)):-
   get_source_of_switch(switch_verbose, user_set),
   command_line_error('Illegal multiple uses of -verbose qualifier\n', []).

% user_rules
%-----------

process_argument(simple_qualifier(nouserrules)):-
    get_source_of_switch(switch_user_rules, auto_set),
    prune_switch_user_rules,
    prune_source_of_switch(switch_user_rules),
    add_switch_user_rules(off),
    add_source_of_switch(switch_user_rules, user_set),
    !.

process_argument(simple_qualifier(nouserrules)):-
    get_source_of_switch(switch_user_rules, user_set),
    command_line_error('Illegal multiple uses of -nouserrules qualifier\n', []).

% plain
%------

process_argument(simple_qualifier(plain)):-
    get_source_of_switch(switch_plain, auto_set),
    prune_switch_plain,
    prune_source_of_switch(switch_plain),
    add_switch_plain(on),
    add_source_of_switch(switch_plain, user_set),
    !.

process_argument(simple_qualifier(plain)):-
   get_source_of_switch(switch_plain, user_set),
   command_line_error('Illegal multiple uses of -plain qualifier\n', []).

% typecheck_only
%---------------

process_argument(simple_qualifier(typecheck)):-
    get_source_of_switch(switch_typecheck_only, auto_set),
    prune_switch_typecheck_only,
    prune_source_of_switch(switch_typecheck_only),
    add_switch_typecheck_only(on),
    add_source_of_switch(switch_typecheck_only, user_set),
    !.

process_argument(simple_qualifier(typecheck)):-
   get_source_of_switch(switch_typecheck_only, user_set),
   command_line_error('Illegal multiple uses of -typecheck qualifier\n', []).

% renum
%------

process_argument(simple_qualifier(norenum)):-
    get_source_of_switch(switch_renum, auto_set),
    prune_switch_renum,
    prune_source_of_switch(switch_renum),
    add_switch_renum(off),
    add_source_of_switch(switch_renum, user_set),
    !.

process_argument(simple_qualifier(norenum)):-
   get_source_of_switch(switch_renum, user_set),
   command_line_error('Illegal multiple uses of -norenum qualifier\n', []).

% simplification
%---------------

process_argument(choices_qualifier(nosimplification, SelectRange)):-
    get_source_of_switch(switch_simplification, auto_set),
    process_selection(SelectRange, SelectVCs),
    prune_switch_simplification,
    prune_source_of_switch(switch_simplification),
    add_switch_simplification(SelectVCs),
    add_source_of_switch(switch_simplification, user_set),
    !.

process_argument(choices_qualifier(nosimplification, _SelectRange)):-
    get_source_of_switch(switch_simplification, user_set),
    command_line_error('Illegal multiple occurrences of -nosimplification qualifier\n', []).

% standardisation
%----------------

process_argument(choices_qualifier(nostandardisation, SelectRange)):-
    get_source_of_switch(switch_standardisation, auto_set),
    process_selection(SelectRange, SelectVCs),
    prune_switch_standardisation,
    prune_source_of_switch(switch_standardisation),
    add_switch_standardisation(SelectVCs),
    add_source_of_switch(switch_standardisation, user_set),
    !.

process_argument(choices_qualifier(nostandardisation, _SelectRange)):-
    get_source_of_switch(switch_standardisation, user_set),
    command_line_error('Illegal multiple occurrences of -nostandardisation qualifier\n', []).

% rule_substitution
%------------------

process_argument(choices_qualifier(norule_substitution, SelectRange)):-
    get_source_of_switch(switch_rule_substitution, auto_set),
    process_selection(SelectRange, SelectVCs),
    prune_switch_rule_substitution,
    prune_source_of_switch(switch_rule_substitution),
    add_switch_rule_substitution(SelectVCs),
    add_source_of_switch(switch_rule_substitution, user_set),
    !.

process_argument(choices_qualifier(norule_substitution, _SelectRange)):-
    get_source_of_switch(switch_rule_substitution, user_set),
    command_line_error('Illegal multiple occurrences of -norule_substitution qualifier\n', []).

% contradiction_hunt
%-------------------

process_argument(choices_qualifier(nocontradiction_hunt, SelectRange)):-
    get_source_of_switch(switch_nocontradiction_hunt, auto_set),
    process_selection(SelectRange, SelectVCs),
    prune_switch_nocontradiction_hunt,
    prune_source_of_switch(switch_nocontradiction_hunt),
    add_switch_nocontradiction_hunt(SelectVCs),
    add_source_of_switch(switch_nocontradiction_hunt, user_set),
    !.

process_argument(choices_qualifier(nocontradiction_hunt, _SelectRange)):-
    get_source_of_switch(switch_nocontradiction_hunt, user_set),
    command_line_error('Illegal multiple occurrences of -nocontradiction_hunt qualifier\n', []).

% substitution_elimination
%-------------------------

process_argument(choices_qualifier(nosubstitution_elimination, SelectRange)):-
    get_source_of_switch(switch_substitution_elimination, auto_set),
    process_selection(SelectRange, SelectVCs),
    prune_switch_substitution_elimination,
    prune_source_of_switch(switch_substitution_elimination),
    add_switch_substitution_elimination(SelectVCs),
    add_source_of_switch(switch_substitution_elimination, user_set),
    !.

process_argument(choices_qualifier(nosubstitution_elimination, _SelectRange)):-
    get_source_of_switch(switch_substitution_elimination, user_set),
    command_line_error('Illegal multiple occurrences of -nosubstitution_elimination qualifier\n', []).

% expression_reduction
%---------------------

process_argument(choices_qualifier(noexpression_reduction, SelectRange)):-
    get_source_of_switch(switch_expression_reduction, auto_set),
    process_selection(SelectRange, SelectVCs),
    prune_switch_expression_reduction,
    prune_source_of_switch(switch_expression_reduction),
    add_switch_expression_reduction(SelectVCs),
    add_source_of_switch(switch_expression_reduction, user_set),
    !.

process_argument(choices_qualifier(noexpression_reduction, _SelectRange)):-
    get_source_of_switch(switch_expression_reduction, user_set),
    command_line_error('Illegal multiple occurrences of -noexpression_reduction qualifier\n', []).

% complexity_limit
%-----------------

process_argument(limit_qualifier(complexity_limit, Int)):-
    get_source_of_switch(switch_complexity_limit, auto_set),
    check_limit_is_valid(Int, complexity_limit, 10, 200),
    prune_switch_complexity_limit,
    prune_source_of_switch(switch_complexity_limit),
    add_switch_complexity_limit(Int),
    add_source_of_switch(switch_complexity_limit, user_set),
    !.

process_argument(limit_qualifier(complexity_limit, _Int)):-
    get_source_of_switch(switch_complexity_limit, user_set),
    command_line_error('Illegal multiple occurrences of -complexity_limit=... qualifier\n', []).

% depth_limit
%------------

process_argument(limit_qualifier(depth_limit, Int)):-
    get_source_of_switch(switch_depth_limit, auto_set),
    check_limit_is_valid(Int, depth_limit, 1, 10),
    prune_switch_depth_limit,
    prune_source_of_switch(switch_depth_limit),
    add_switch_depth_limit(Int),
    add_source_of_switch(switch_depth_limit, user_set),
    !.

process_argument(limit_qualifier(depth_limit, _Int)):-
    get_source_of_switch(switch_depth_limit, user_set),
    command_line_error('Illegal multiple occurrences of -depth_limit=... qualifier\n', []).

% inference_limit
%----------------

process_argument(limit_qualifier(inference_limit, Int)):-
    get_source_of_switch(switch_inference_limit, auto_set),
    check_limit_is_valid(Int, inference_limit, 10, 400),
    prune_switch_inference_limit,
    prune_source_of_switch(switch_inference_limit),
    add_switch_inference_limit(Int),
    add_source_of_switch(switch_inference_limit, auto_set),
    !.

process_argument(limit_qualifier(inference_limit, _Int)):-
    get_source_of_switch(switch_inference_limit, user_set),
    command_line_error('Illegal multiple occurrences of -inference_limit=... qualifier\n', []).

% help
%-----

process_argument(simple_qualifier(help)):-
    get_source_of_switch(switch_help, auto_set),
    prune_switch_help,
    prune_source_of_switch(switch_help),
    add_switch_help(on),
    add_source_of_switch(switch_help, user_set),
    !.

process_argument(simple_qualifier(help)):-
    get_source_of_switch(switch_help, user_set),
    command_line_error('Illegal multiple uses of -help qualifier\n', []).

% version
%--------

process_argument(simple_qualifier(version)):-
    get_source_of_switch(switch_version, auto_set),
    prune_switch_version,
    prune_source_of_switch(switch_version),
    add_switch_version(on),
    add_source_of_switch(switch_version, user_set),
    !.

process_argument(simple_qualifier(version)):-
    get_source_of_switch(switch_version, user_set),
    command_line_error('Illegal multiple uses of -version qualifier\n', []).

% Usage
%--------

% First occurrence of a log switch (here /log=...).
process_argument(usage_qualifier(UsageFile_Atom)):-
    get_source_of_switch(switch_usage, auto_set),
    prune_switch_usage,
    prune_source_of_switch(switch_usage),
    add_switch_usage(provided_usage_file(UsageFile_Atom)),
    add_source_of_switch(switch_usage, user_set),
    !.

% Hypothesis limit for ZombieScope
%-------------------

process_argument(limit_qualifier(hyp_limit, Limit)):-
    integer(Limit),
    process_argument_hyp_limit(Limit),
    !.

process_argument(limit_qualifier(hyp_limit, none)):-
    process_argument_hyp_limit(none),
    !.

process_argument(choices_qualifier(hyp_limit, _Limit)):-
    get_source_of_switch(switch_hyp_limit, user_set),
    command_line_error('Illegal multiple occurrences of -hyp_limit=... qualifier\n', []).

% unexpected
%-----------

process_argument(CMDLine):-
    throw_error('Unexpected parsed command line argument: ~w\n', [CMDLine]).


% Set the hyp limit switch.
%-----------

process_argument_hyp_limit(Limit):-
    get_source_of_switch(switch_hyp_limit, auto_set),
    prune_switch_hyp_limit,
    prune_source_of_switch(switch_hyp_limit),
    add_switch_hyp_limit(Limit),
    add_source_of_switch(switch_hyp_limit, user_set),
    !.

%===============================================================================

%===============================================================================
% process_selection(+SelectRange, -SelectVCs).
%-------------------------------------------------------------------------------
% Transform a range selection (SelectRange) into a more accessible vc
% selection (SelectVCs), with some error checking for bad ranges.
%===============================================================================

% Applies to all.
process_selection(all, all):-
    !.

% Applies to none.
process_selection(none, none):-
    !.

% Applies to those in range.
process_selection(specific(Range_List), exclude(IntList)):-
    convert_range_list_as_int_list(Range_List, IntList),
    !.

%-------------------------------------------------------------------------------

convert_range_list_as_int_list(Range_List, IntList):-
    range_to_list(Range_List, IntListList),
    flatten_list(IntListList, IntList),
    convert_range_list_as_int_list_x(IntList),
    !.

%-------------------------------------------------------------------------------

convert_range_list_as_int_list_x(IntList):-
    contains_no_dups(IntList),
    !.

convert_range_list_as_int_list_x(_IntList):-
    command_line_error('Illegal duplication in list of argument numbers\n', []).

%-------------------------------------------------------------------------------

range_to_list([], []):-
    !.

range_to_list([H_Range | T_Range_List],
	      [H_IntList | T_IntListList]):-
    convert_one_range_to_list(H_Range, H_IntList),
    range_to_list(T_Range_List, T_IntListList),
    !.

%-------------------------------------------------------------------------------

% Specific value.
convert_one_range_to_list(value(Int), [Int]):-
    integer(Int),
    Int > 0,
    !.

convert_one_range_to_list(value(_Int), _IntList):-
    command_line_error('Illegal entry in list of numbers argument\n', []).

% Range of values.
convert_one_range_to_list(range(Lower_Int, Upper_Int), IntList):-
    integer(Lower_Int),
    integer(Upper_Int),
    Lower_Int > 0,
    Lower_Int < Upper_Int,
    generate_int_list(Lower_Int, Upper_Int, IntList),
    !.

convert_one_range_to_list(range(_Lower_Int, _Upper_Int), _IntList):-
    command_line_error('Illegal entry in list of numbers argument\n', []).

%===============================================================================
% check_limit_is_valid(+Int, +Limit_Atom, +LowerLegal_Int, +UpperLegal_Int).
%-------------------------------------------------------------------------------
% Check that provided limit is valid, aborting with error if not.
%===============================================================================

check_limit_is_valid(Int, _Limit_Atom, LowerLegal_Int, UpperLegal_Int):-
    integer(Int),
    Int >= LowerLegal_Int,
    Int =< UpperLegal_Int,
    !.

check_limit_is_valid(Int, Limit_Atom, LowerLegal_Int, UpperLegal_Int):-
    command_line_error('Value ~d given for -~a is out of permitted range: ~d to ~d\n',
                      [Int,
                       Limit_Atom,
                       LowerLegal_Int,
                       UpperLegal_Int]).


:- set_prolog_flag(double_quotes, codes).

%###############################################################################
% END-OF-FILE
