% -----------------------------------------------------------------------------
%  (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.
% 
% =============================================================================


checktype(E, T) :-
        nonvar(T),
        !,
        find_core_type(T, CT),
        !,
        (
           checkhastype(E, CT)
        ;
           CT = real,
           checkhastype(E, integer)
        ),
        !.
checktype(E, T) :-
        checkhastype(E, TYPE),
        !,
        (
           T = TYPE
        ;
           TYPE = integer,
           !,
           T = real
        ;                                                       /* CFR036 */
           E =.. [mk__record|_],                                /* CFR036 */
           !,                                                   /* CFR036 */
           compatible_record_type(TYPE, T),                     /* CFR036 */
           checkhastype(E, T)                                   /* CFR036 */
        ;                                                       /* CFR036 */
           E =.. [mk__array|_],                                 /* CFR036 */
           !,                                                   /* CFR036 */
           compatible_array_type(TYPE, T),                      /* CFR036 */
           checkhastype(E, T)                                   /* CFR036 */
        ).

checktypes([E|EL], [T|TL]) :-
        checktype(E, T),
        checktypes(EL, TL).
checktypes([], []).

/* BOOL1 */  checkhastype(true, boolean) :- !.
/* BOOL2 */  checkhastype(false, boolean) :- !.
/* BOOL3 */  checkhastype(for_all(V:AT, FORMULA), boolean) :-
                !,
                atom(V),
                find_core_type(AT, T),
                (
                   type(T, _)
                ;
                   T = integer
                ;
                   T = real
                ;
                   T = boolean
                ),
                !,
                (
                   var_const(V, T, v),
                   !,
                   checkhastype(FORMULA, boolean)
                ;
                   asserta(var_const(V, T, v)),
                   checkhastype(FORMULA, boolean),
                   retract(var_const(V, T, v)),
                   !
                ;
                   retract(var_const(V, T, v)),
                   fail
                ), !.
/* BOOL4 */  checkhastype(for_some(V:AT, FORMULA), boolean) :-
                !,
                atom(V),
                find_core_type(AT, T),
                (
                   type(T, _)
                ;
                   T = integer
                ;
                   T = real
                ;
                   T = boolean
                ),
                !,
                (
                   var_const(V, T, v),
                   !,
                   checkhastype(FORMULA, boolean)
                ;
                   asserta(var_const(V, T, v)),
                   checkhastype(FORMULA, boolean),
                   retract(var_const(V, T, v)),
                   !
                ;
                   retract(var_const(V, T, v)),
                   fail
                ), !.

/* I/R1 */   checkhastype(X+Y, IR) :-
                checkhastype(X, IRX),
                !,
                checkhastype(Y, IRY),
                !,
                (
                   (
                      IRX=real
                   ;
                      IRY=real
                   ),
                   !,
                   IR=real
                ;
                   IRX=integer,
                   IRY=integer,
                   (IR=integer ; IR=real)
                ),
                !.
/* I/R2 */   checkhastype(X-Y, IR) :-
                checkhastype(X, IRX),
                !,
                checkhastype(Y, IRY),
                !,
                (
                   (
                      IRX=real
                   ;
                      IRY=real
                   ),
                   !,
                   IR=real
                ;
                   IRX=integer,
                   IRY=integer,
                   (IR=integer ; IR=real)
                ),
                !.
/* I/R3 */   checkhastype(X*Y, IR) :-
                checkhastype(X, IRX),
                !,
                checkhastype(Y, IRY),
                !,
                (
                   (
                      IRX=real
                   ;
                      IRY=real
                   ),
                   !,
                   IR=real
                ;
                   IRX=integer,
                   IRY=integer,
                   (IR=integer ; IR=real)
                ),
                !.
/* I/R4 */   checkhastype(-X, IR) :-
                checkhastype(X, IRX),
                !,
                (
                   IRX=real,
                   IR=real
                ;
                   IRX=integer,
                   (IR=integer ; IR=real)
                ),
                !.

/* INT1 */   checkhastype(X div Y, integer) :-
                checkhastype(X, integer), !,
                checkhastype(Y, integer), !.
/* INT2 */   checkhastype(X mod Y, integer) :-
                checkhastype(X, integer), !,
                checkhastype(Y, integer), !.

/* I/R5 */   checkhastype(abs(X), IR) :-
                checkhastype(X, IRX), !,
                (
                   IRX=real,
                   IR=real
                ;
                   IRX=integer,
                   (IR=integer ; IR=real)
                ),
                !.
/* I/R6 */   checkhastype(sqr(X), IR) :-
                checkhastype(X, IRX), !,
                (
                   IRX=real,
                   IR=real
                ;
                   IRX=integer,
                   (IR=integer ; IR=real)
                ),
                !.
/* I/R7 */   checkhastype(X ** Y, IR) :-                        /* CFR038 */
                checkhastype(Y, integer),                       /* CFR038 */
                checkhastype(X, IR),                            /* CFR038 */
                ( IR = integer ; IR = real ),                   /* CFR038 */
                !.                                              /* CFR038 */
/* I/R8 */   checkhastype(+X, IR) :-                            /* CFR039 */
                checkhastype(X, IR),                            /* CFR039 */
                !,                                              /* CFR039 */
                ( IR=real ; IR=integer ),                       /* CFR039 */
                !.                                              /* CFR039 */

/* REA1 */   checkhastype(X/Y, real) :-
                checkhastype(X, real), !,
                checkhastype(Y, real), !.

/* REL1 */   checkhastype(X=Y, boolean) :-
                checkhastype(X, TX),
                (
                   (
                      TX=integer
                   ;
                      TX=real
                   ),
                   !,
                   checkhastype(Y, TY),
                   (
                        TY=integer
                   ;
                        TY=real
                   )
                ;
                   checkhastype(Y, TX)
                ), !.
/* REL2 */   checkhastype(X<>Y, boolean) :-
                checkhastype(X, TX),
                (
                   (
                      TX=integer
                   ;
                      TX=real
                   ),
                   !,
                   checkhastype(Y, TY),
                   (
                        TY=integer
                   ;
                        TY=real
                   )
                ;
                   checkhastype(Y, TX)
                ), !.
/* REL3 */   checkhastype(X>Y, boolean) :-
                checkhastype(X, TX),
                (
                   (
                      TX=integer
                   ;
                      TX=real
                   ),
                   !,
                   checkhastype(Y, TY),
                   (
                        TY=integer
                   ;
                        TY=real
                   )
                ;
                   type(TX, enumerated),
                   checkhastype(Y, TX)
                ), !.
/* REL4 */   checkhastype(X<Y, boolean) :-
                checkhastype(X, TX),
                (
                   (
                      TX=integer
                   ;
                      TX=real
                   ),
                   !,
                   checkhastype(Y, TY),
                   (
                        TY=integer
                   ;
                        TY=real
                   )
                ;
                   type(TX, enumerated),
                   checkhastype(Y, TX)
                ), !.
/* REL5 */   checkhastype(X>=Y, boolean) :-
                checkhastype(X, TX),
                (
                   (
                      TX=integer
                   ;
                      TX=real
                   ),
                   !,
                   checkhastype(Y, TY),
                   (
                        TY=integer
                   ;
                        TY=real
                   )
                ;
                   type(TX, enumerated),
                   checkhastype(Y, TX)
                ), !.
/* REL6 */   checkhastype(X<=Y, boolean) :-
                checkhastype(X, TX),
                (
                   (
                      TX=integer
                   ;
                      TX=real
                   ),
                   !,
                   checkhastype(Y, TY),
                   (
                        TY=integer
                   ;
                        TY=real
                   )
                ;
                   type(TX, enumerated),
                   checkhastype(Y, TX)
                ), !.

/* ARR1 */   checkhastype(update(A, IL, E), T) :-
                checkhastype(A, T),
                (                                               /*1.4*/
                   type(T, array(ITL, ET))                      /*1.4*/
                ;                                               /*1.4*/
                   find_core_type(T, TN),                       /*1.4*/
                   type(TN, array(ITL, ET))                     /*1.4*/
                ),                                              /*1.4*/
                checkhastypelist(IL, ITL),
                checkhastype(E, ET), !.
/* ARR2 */   checkhastype(element(A, IL), ET) :-
                checkhastype(A, T),
                (                                               /*1.4*/
                   type(T, array(ITL, ET))                      /*1.4*/
                ;                                               /*1.4*/
                   find_core_type(T, TN),                       /*1.4*/
                   type(TN, array(ITL, ET))                     /*1.4*/
                ),                                              /*1.4*/
                checkhastypelist(IL, ITL), !.

/* BOOL5 */  checkhastype((not X), boolean) :-
                checkhastype(X, boolean), !.
/* BOOL6 */  checkhastype(X and Y, boolean) :-
                checkhastype(X, boolean), !,
                checkhastype(Y, boolean), !.
/* BOOL7 */  checkhastype(X or Y, boolean) :-
                checkhastype(X, boolean), !,
                checkhastype(Y, boolean), !.
/* BOOL8 */  checkhastype(X -> Y, boolean) :-
                checkhastype(X, boolean), !,
                checkhastype(Y, boolean), !.
/* BOOL9 */  checkhastype(X <-> Y, boolean) :-
                checkhastype(X, boolean), !,
                checkhastype(Y, boolean), !.

/* INT3 */   checkhastype(A, integer) :- integer(A), !.

/* TYP1 */   checkhastype(A, T) :-
                atomic(A),
                var_const(A, T, _), !.

/*  ODD  */  checkhastype(odd(X), boolean) :-
                checkhastype(X, integer), !.

/* ORD1 */   checkhastype(pred(X), T) :-
                checkhastype(X, T), !,
                (type(T,enumerated) ; T=integer), !.
/* ORD2 */   checkhastype(succ(X), T) :-
                checkhastype(X, T), !,
                (type(T,enumerated) ; T=integer), !.

/* SEQ1 */   checkhastype(length(S), integer) :-
                checkhastype(S, ST), !, type(ST, sequence(_)), !.
/* SEQ2 */   checkhastype(first(S), ET) :-
                checkhastype(S, ST), type(ST, sequence(ET)).
/* SEQ3 */   checkhastype(last(S), ET) :-
                checkhastype(S, ST), type(ST, sequence(ET)).
/* SEQ4 */   checkhastype(nonfirst(S), ST) :-
                checkhastype(S, ST), type(ST, sequence(_)).
/* SEQ5 */   checkhastype(nonlast(S), ST) :-
                checkhastype(S, ST), type(ST, sequence(_)).
/* SEQ6 */   checkhastype(X @ Y, ST) :-
                checkhastype(X, ST),
                type(ST, sequence(_)),
                checkhastype(Y, ST).

/* SET1 */   checkhastype(X \/ Y, ST) :-
                checkhastype(X, ST),
                type(ST, set(_)),
                checkhastype(Y, ST).
/* SET2 */   checkhastype(X \ Y, ST) :-
                checkhastype(X, ST),
                type(ST, set(_)),
                checkhastype(Y, ST).
/* SET3 */   checkhastype(X /\ Y, ST) :-
                checkhastype(X, ST),
                type(ST, set(_)),
                checkhastype(Y, ST).
/* SET4 */   checkhastype(X in Y, boolean) :-
                checkhastype(Y, ST),
                type(ST, set(ET)),
                checkhastype(X, ET), !.
/* SET5 */   checkhastype(X not_in Y, boolean) :-
                checkhastype(Y, ST),
                type(ST, set(ET)),
                checkhastype(X, ET), !.
/* SET6 */   checkhastype(X subset_of Y, boolean) :-
                checkhastype(X, ST),
                type(ST, set(_)),
                checkhastype(Y, ST), !.
/* SET7 */   checkhastype(X strict_subset_of Y, boolean) :-
                checkhastype(X, ST),
                type(ST, set(_)),
                checkhastype(Y, ST), !.

/* SEQ7 */   checkhastype([], T) :- type(T, sequence(_)).
/* SEQ8 */   checkhastype([E|EL], T) :-
                checkhastype(E, ET),
                type(T, sequence(ET)),
                checkhastype(EL, T).

/* SET8 */   checkhastype(set [], T) :- type(T, set(_)).
/* SET9 */   checkhastype(set [E|EL], T) :-
                checkhastype(E, ET),
                type(T, set(ET)),
                checkhastype(set EL, T).

/* ARR3 */   checkhastype(mk__array(VALUE), T) :-               /* CFR036 */
                (
                   type(T, array([IT], VT))                     /* 036,1.4*/
                ;                                               /*1.4*/
                   find_core_type(T, TN),                       /*1.4*/
                   type(TN, array([IT], VT))                    /*1.4*/
                ),                                              /*1.4*/
                VALUE \= (_ := _),                              /* CFR036 */
                checktype(VALUE, VT).                           /* CFR036 */
/* ARR4 */   checkhastype(AGG, T) :-                            /* CFR036 */
                \+ atomic(AGG),                         /* CFR036 */
                AGG =.. [F|ARGS],                               /* CFR036 */
                spark_enabled,                                  /* CFR036 */
                (                                               /* CFR036 */
                   F = mk__array,                               /* CFR036 */
                   !,                                           /* CFR036 */
                   collect_indices_and_values(                  /* CFR036 */
                        ARGS, [I|INDS], [V|VALS]),              /* CFR036 */
                   !,                                           /* CFR036 */
                   checktype(I, IT),                            /* CFR036 */
                   checkrestoflist(INDS, IT),                   /* CFR036 */
                   checktype(V, VT),                            /* CFR036 */
                   checkrestoflist(VALS, VT),                   /* CFR036 */
                   type(T, array([IT], VT))                     /* CFR036 */
                ;                                               /* CFR036 */
                   F = mk__record,                              /* CFR036 */
                   !,                                           /* CFR036 */
                   collect_fields_and_values(                   /* CFR036 */
                        ARGS, FIELDS, VALUES),                  /* CFR036 */
                   type(T, record(RECFIELDS)),                  /* CFR036 */
                   permutation_of_fields(                       /* CFR036 */
                        FIELDS, RECFIELDS, TYPES),              /* CFR036 */
                   checktypelist(VALUES, TYPES)                 /* CFR036 */
                ).                                              /* CFR036 */

/* ARR5 */   checkhastype(E, T) :-
                \+ atomic(E),
                E =.. [F,Arg],
                mk__function_name(F, TN, array),
                Arg \= (_ := _),                                /*1.4*/
                !,
                (                                               /*1.4*/
                   type(TN, array([IT], VT)),                   /*1.4*/
                   T = TN                                       /*1.4*/
                ;                                               /*1.4*/
                   find_core_type(TN, T),                       /*1.4*/
                   type(T, array([IT], VT))                     /*1.4*/
                ),                                              /*1.4*/
                checktype(Arg, VT).
/* ARR6 */   checkhastype(AGG, T) :-
                \+ atomic(AGG),
                AGG =.. [F|ARGS],
                spark_enabled,
                (
                   mk__function_name(F , TN, array),
                   !,
                   collect_indices_and_values(
                        ARGS, [I|INDS], [V|VALS]),
                   !,
                   checktype(I, IT),
                   checkrestoflist(INDS, IT),
                   checktype(V, VT),
                   checkrestoflist(VALS, VT),
                   (                                            /*1.4*/
                      type(TN, array([IT], VT)),                /*1.4*/
                      T = TN                                    /*1.4*/
                   ;                                            /*1.4*/
                      find_core_type(TN, T),                    /*1.4*/
                      type(T, array([IT], VT))                  /*1.4*/
                   )                                            /*1.4*/
                ;
                   mk__function_name(F, T, record),
                   !,
                   collect_fields_and_values(
                        ARGS, FIELDS, VALUES),
                   type(T, record(RECFIELDS)),
                   permutation_of_fields(
                        FIELDS, RECFIELDS, TYPES),
                   checktypelist(VALUES, TYPES)
                ).

/* FUNC */   checkhastype(A, T) :-
                \+ atomic(A),
                function_template(A, AL, F),
                checktypelist(AL, ATL),
                (
                   function(F, ATLX, T)
                ;
                   function(F, ATLX, XT),
                   compatible_type_lists([XT], [T])
                ),
                compatible_type_lists(ATL, ATLX),
                !.

/* REC1 */   checkhastype(A, T) :-                              /* CFR029 */
                \+ atomic(A),                                   /* CFR029 */
                record_function(_N, A, access, _FIELD, [REC], _), /* CFR029,053 */
                checkhastype(REC, RTYPE),                       /* CFR029 */
                A =.. [F|_],                                    /* CFR029 */
                (                                               /* CFR029 */
                   function(F, [RTYPE], T)                      /* CFR029 */
                ;                                               /* CFR029 */
                   function(F, [RTYPE], XT),                    /* CFR029 */
                   compatible_type_lists([XT], [T])             /* CFR029 */
                ),                                              /* CFR029 */
                !.                                              /* CFR029 */

/* REC2 */   checkhastype(A, RTYPE) :-                          /* CFR029 */
                \+ atomic(A),                                   /* CFR029 */
                record_function(_N, A, update, _FIELD, [R,V], _), /* CFR029,053 */
                checkhastype(R, RTYPE),                         /* CFR029 */
                A =.. [F|_],                                    /* CFR029 */
                function(F, [RTYPE,VTYPE], RTYPE),              /* CFR029 */
                checkhastype(V, VTYPE),                         /* CFR029 */
                !.                                              /* CFR029 */

/* UNIV */   checkhastype(A, T) :-
                \+ atomic(A),
                \+ function_template(A, _, _),
                \+ record_function(_, A, _, _, _, _),           /* CFR029,053 */
                A=..[F|ARGS],
                check_is_an_ok_arity_function(F, ARGS),
                checktypelist(ARGS, ATL),
                (
                   function(F, ATLX, T)
                ;
                   function(F, ATLX, XT),
                   compatible_type_lists([XT], [T])
                ),
                compatible_type_lists(ATL, ATLX),
                !.

/* BITWISE1 */
checkhastype(bit__and(X,Y), Z) :-
      spark_enabled,
      checkhastype(X, Z),
      checkhastype(Y, Z),
      !.

/* BITWISE2 */
checkhastype(bit__or(X,Y), integer) :-
      spark_enabled,
      checkhastype(X, integer),
      checkhastype(Y, integer),
      !.

/* BITWISE3 */
checkhastype(bit__xor(X,Y), integer) :-
      spark_enabled,
      checkhastype(X, integer),
      checkhastype(Y, integer),
      !.

/* REA2 */   checkhastype(X, real) :-
                checkhastype(X, integer), !.


/* CTL1 */   checktypelist([E], [T]) :- !, checkhastype(E, T), !.
/* CTL2 */   checktypelist([E|EL], [T|TL]) :-
                checkhastype(E, T),
                checktypelist(EL, TL), !.

/* CHL1 */   checkhastypelist([E], [T]) :- !, checkhastype(E, T), !.
/* CHL2 */   checkhastypelist([E|EL], [T|TL]) :-
                checkhastype(E, T), !,
                checkhastypelist(EL, TL), !.
/* CHL3 */   checkhastypelist([E], T) :- !, checkhastype(E, T), !.
/* CHL4 */   checkhastypelist([E|EL], T) :-
                checkhastype(E, T), !,
                checkhastypelist(EL, T),
                !.


compatible_type_lists([A], [A]) :- !.
compatible_type_lists([integer], [real]) :- !.
compatible_type_lists([A|AL], [A|RL]) :- compatible_type_lists(AL, RL), !.
compatible_type_lists([integer|AL],[real|RL]) :- compatible_type_lists(AL,RL),!.
compatible_type_lists([T1|AL],[T2|RL]) :-
        compatible_set_or_seq_types(T1, T2),
        !,
        compatible_type_lists(AL, RL), !.
compatible_type_lists([], []) :- !.


compatible_set_or_seq_types(T1, T2) :-
        type(T1, set(ET1)),
        type(T2, set(ET2)),
        !,
        compatible_type_lists([ET1],[ET2]), !.
compatible_set_or_seq_types(T1, T2) :-
        type(T1, sequence(ET1)),
        type(T2, sequence(ET2)),
        !,
        compatible_type_lists([ET1],[ET2]), !.


check_is_an_ok_arity_function(F, ARGS) :-
        function(F, ARGL, _),
        length(ARGL, LEN),
        length(ARGS, LEN),
        !.


save_type_classification(E) :- type_classification(E, _X), !.
save_type_classification(E) :-
        checktype(E, T),
        (
           T = integer,
           !,
           maybe_add(type_classification(E, i))
        ;
           T = real,
           !,
           maybe_add(type_classification(E, r))
        ;
           type(T, enumerated),
           !,
           maybe_add(type_classification(E, e))
        ;
           true
        ), !.
save_type_classification(_E) :- !.


save_type_classification_list([E|L]) :-
        save_type_classification(E),
        save_type_classification_list(L),
        !.
save_type_classification_list([]) :- !.


has_type_classification(E, C) :- type_classification(E, C), !.
has_type_classification(E, ir) :-
        (
           type_classification(E, i)
        ;
           type_classification(E, r)
        ), !.
has_type_classification(E, ire) :-
        (
           type_classification(E, i)
        ;
           type_classification(E, r)
        ;
           type_classification(E, e)
        ), !.
has_type_classification(_E, any) :- !.


has_type_classification_list([]) :- !.
has_type_classification_list(X) :-
        (
           type_classification_done,
           !,
           check_has_type_classifications_list(X)
        ;
           var_free(X),
           ensure_has_type_classifications_list(X)
        ),
        !.


check_has_type_classifications_list([F:T | REST]) :-
        has_type_classification(F, T),
        check_has_type_classifications_list(REST),
        !.
check_has_type_classifications_list([]) :- !.


ensure_has_type_classifications_list([F:T | REST]) :-
        save_type_classification(F),
        has_type_classification(F, T),
        ensure_has_type_classifications_list(REST),
        !.
ensure_has_type_classifications_list([]) :- !.


compatible_record_type(T1, T2) :-                               /* CFR036 */
        type(T1, record(F1)),                                   /* CFR036 */
        type(T2, record(F2)),                                   /* CFR036 */
        T1 \= T2,                                               /* CFR036 */
        same_record_field_names(F1, F2).                        /* CFR036 */


same_record_field_names(Fs, Gs) :-                              /* CFR036 */
        collect_record_field_names(Fs, Fn),                     /* CFR036 */
        collect_record_field_names(Gs, Gn),                     /* CFR036 */
        sort(Fn, S),                                            /* CFR036 */
        sort(Gn, S),                                            /* CFR036 */
        !.                                                      /* CFR036 */

collect_record_field_names([[F,_]|FTs], [F|Fs]) :-              /* CFR036 */
        !,                                                      /* CFR036 */
        collect_record_field_names(FTs, Fs).                    /* CFR036 */
collect_record_field_names([], []) :- !.                        /* CFR036 */


compatible_array_type(T1, T2) :-                                /* CFR036 */
        type(T1, array(I1, R1)),                                /* CFR036 */
        type(T2, array(I2, R2)),                                /* CFR036 */
        T1 \= T2,                                               /* CFR036 */
        compatible_array_result_types(R1, R2),                  /* CFR036 */
        compatible_array_indices(I1, I2).                       /* CFR036 */


compatible_array_result_types(T, T) :- !.                       /* CFR036 */
compatible_array_result_types(integer, real) :- !.              /* CFR036 */
compatible_array_result_types(real, integer) :- !.              /* CFR036 */
compatible_array_result_types(T1, T2) :-                        /* CFR036 */
        compatible_record_type(T1, T2),                         /* CFR036 */
        !.                                                      /* CFR036 */


compatible_array_indices([I|Is], [I|Js]) :-                     /* CFR036 */
        !,                                                      /* CFR036 */
        compatible_array_indices(Is, Js).                       /* CFR036 */
compatible_array_indices([], []) :- !.                          /* CFR036 */


collect_indices_and_values([A|ARGS], INDS, [V|VALS]) :-         /* CFR036 */
        (                                                       /* CFR036 */
           A = (LHS := V),                                      /* CFR036 */
           collect_indices(LHS, I),                             /* CFR036 */
           collect_indices_and_values(ARGS, RESTINDS, VALS),    /* CFR036 */
           !,                                                   /* CFR036 */
           append(I, RESTINDS, INDS)                            /* CFR036 */
        ;                                                       /* CFR036 */
           V = A,                                               /* CFR036 */
           !,                                                   /* CFR036 */
           collect_indices_and_values(ARGS, INDS, VALS)         /* CFR036 */
        ),                                                      /* CFR036 */
        !.                                                      /* CFR036 */
collect_indices_and_values([], [], []) :- !.                    /* CFR036 */


collect_indices(X & Y, I) :-                                    /* CFR036 */
        collect_indices(X, XL),                                 /* CFR036 */
        collect_indices(Y, YL),                                 /* CFR036 */
        !,                                                      /* CFR036 */
        append(XL, YL, I),                                      /* CFR036 */
        !.                                                      /* CFR036 */
collect_indices([X .. Y], [X,Y]) :- !.                          /* CFR036 */
collect_indices([X], [X]) :- !.                                 /* CFR036 */


collect_fields_and_values([(F := V)|ARGS], [F|Fs], [V|Vs]) :-   /* CFR036 */
        !,                                                      /* CFR036 */
        collect_fields_and_values(ARGS, Fs, Vs),                /* CFR036 */
        !.                                                      /* CFR036 */
collect_fields_and_values([], [], []) :- !.                     /* CFR036 */


permutation_of_fields([F|FIELDS], FTL, [T|TYPES]) :-            /* CFR036 */
        gen_append(LHS, [[F,T]|RHS], FTL),                      /* CFR036 */
        !,                                                      /* CFR036 */
        append(LHS, RHS, NEWFTL),                               /* CFR036 */
        !,                                                      /* CFR036 */
        permutation_of_fields(FIELDS, NEWFTL, TYPES),           /* CFR036 */
        !.                                                      /* CFR036 */
permutation_of_fields([], [], []) :- !.                         /* CFR036 */


checkrestoflist([X|XL], T) :-                                   /* CFR036 */
        checktype(X, T),                                        /* CFR036 */
        checkrestoflist(XL, T).                                 /* CFR036 */
checkrestoflist([], _).                                         /* CFR036 */
%###############################################################################
%END-OF-FILE
