From 0db2ced21baefc8ef8b9d19a832b3133f8b2e21d Mon Sep 17 00:00:00 2001 From: Alexandre Duret-Lutz Date: Thu, 14 Nov 2002 16:11:54 +0000 Subject: [PATCH] * lib/Automake/Conditional.pm: Add reference to ConditionalSet.pm. * lib/Automake/ConditionalSet.pm: New file. * lib/Automake/Makefile.am (dist_perllib_DATA): Add ConditionalSet.pm. * automake.in: Use ConditionalSet. (by_condition, invert_conditions, variable_conditions_permutations): Remove, now defined as Automake::ConditionalSet::by_condition, Automake::ConditionalSet::invert, and Automake::ConditionalSet::permutations. (variable_sorted_conditions): Remove. (msg_var, msg_target handle_source_transform, handle_lib_objects, conditional_ambiguous_p, variable_not_always_defined_in_cond, macro_define, macro_dump, variable_defined, variable_conditions_recursive, variable_conditions, target_conditions, variable_conditionally_defined, variable_conditions_recursive_sub, check_variable_defined_unconditionally, variable_value_as_list, variable_value_as_list_recursive_worker, variable_output, variable_pretty_output, rule_define, append_exeext, am_install_var, require_variables_for_macro): Adjust to use ConditionalSet. --- ChangeLog | 23 ++ automake.in | 196 ++++------------ lib/Automake/Conditional.pm | 6 +- lib/Automake/ConditionalSet.pm | 416 +++++++++++++++++++++++++++++++++ lib/Automake/Makefile.am | 1 + lib/Automake/Makefile.in | 1 + 6 files changed, 487 insertions(+), 156 deletions(-) create mode 100644 lib/Automake/ConditionalSet.pm diff --git a/ChangeLog b/ChangeLog index 19471d89..01b6e642 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2002-11-14 Alexandre Duret-Lutz + + * lib/Automake/Conditional.pm: Add reference to ConditionalSet.pm. + * lib/Automake/ConditionalSet.pm: New file. + * lib/Automake/Makefile.am (dist_perllib_DATA): Add ConditionalSet.pm. + * automake.in: Use ConditionalSet. + (by_condition, invert_conditions, variable_conditions_permutations): + Remove, now defined as Automake::ConditionalSet::by_condition, + Automake::ConditionalSet::invert, and + Automake::ConditionalSet::permutations. + (variable_sorted_conditions): Remove. + (msg_var, msg_target handle_source_transform, handle_lib_objects, + conditional_ambiguous_p, variable_not_always_defined_in_cond, + macro_define, macro_dump, variable_defined, + variable_conditions_recursive, variable_conditions, + target_conditions, variable_conditionally_defined, + variable_conditions_recursive_sub, + check_variable_defined_unconditionally, variable_value_as_list, + variable_value_as_list_recursive_worker, variable_output, + variable_pretty_output, rule_define, append_exeext, + am_install_var, require_variables_for_macro): Adjust to + use ConditionalSet. + 2002-11-13 Alexandre Duret-Lutz * automake.in (variable_conditions): Split into ... diff --git a/automake.in b/automake.in index 83ca6478..ba385a21 100755 --- a/automake.in +++ b/automake.in @@ -117,6 +117,7 @@ use Automake::XFile; use Automake::Channels; use Automake::Location; use Automake::Conditional qw/TRUE FALSE/; +use Automake::ConditionalSet; use File::Basename; use Tie::RefHash; use Carp; @@ -1248,7 +1249,7 @@ sub msg_var ($$$;%) { my ($channel, $var, $msg, %opts) = @_; # Don't know which condition is concerned. Pick any. - my $cond = (variable_conditions ($var))[0]; + my $cond = variable_conditions ($var)->one_cond; msg_cond_var $channel, $cond, $var, $msg, %opts; } @@ -1268,7 +1269,7 @@ sub msg_target ($$$;%) { my ($channel, $target, $msg, %opts) = @_; # Don't know which condition is concerned. Pick any. - my $cond = (target_conditions ($target))[0]; + my $cond = target_conditions ($target)->one_cond; msg_cond_target ($channel, $cond, $target, $msg, %opts); } @@ -2655,7 +2656,7 @@ sub define_objects_from_sources ($$$$$$$$) my $needlinker = ""; my @allresults = (); - foreach my $cond (variable_sorted_conditions ($var)) + foreach my $cond (variable_conditions ($var)->conds) { my @result; foreach my $val (&variable_value_as_list ($var, $cond, $parent)) @@ -2827,7 +2828,7 @@ sub handle_source_transform # am__VAR_DIST variable which contains all possible values, # and add this variable to DIST_SOURCES. my $distvar = "$var"; - my @conds = variable_conditions_recursive ($var); + my @conds = variable_conditions_recursive ($var)->conds; if (@conds && $conds[0] != TRUE) { $distvar = "am__${var}_DIST"; @@ -2901,7 +2902,7 @@ sub handle_lib_objects if ! variable_defined ($var); my $ret = 0; - foreach my $cond (variable_conditions_recursive ($var)) + foreach my $cond (variable_conditions_recursive ($var)->conds) { if (&handle_lib_objects_cond ($xname, $var, $cond)) { @@ -5941,24 +5942,6 @@ sub condition_negate ($) } -# Compare condition names. -# Issue them in alphabetical order, foo_TRUE before foo_FALSE. -sub by_condition -{ - # Be careful we might be comparing `' or `#'. - $a->string =~ /^(.*)_(TRUE|FALSE)$/; - my ($aname, $abool) = ($1 || '', $2 || ''); - $b->string =~ /^(.*)_(TRUE|FALSE)$/; - my ($bname, $bbool) = ($1 || '', $2 || ''); - return ($aname cmp $bname - # Don't bother with IFs, given that TRUE is after FALSE - # just cmp in the reverse order. - || $bbool cmp $abool - # Just in case... - || $a cmp $b); -} - - ## ------------------------------ ## ## Handling the condition stack. ## ## ------------------------------ ## @@ -6079,18 +6062,18 @@ sub check_ambiguous_conditional ($$$) } # $STRING, $AMBIG_COND -# conditional_ambiguous_p ($WHAT, $COND, @CONDS) +# conditional_ambiguous_p ($WHAT, $COND, $CONDSET) # ---------------------------------------------- # Check for an ambiguous conditional. Return an error message and # the other condition involved if we have one, two empty strings otherwise. -# WHAT: the thing being defined -# COND: the condition under which is is being defined -# CONDS: the conditons under which is had already been defined -sub conditional_ambiguous_p ($$@) +# WHAT: the thing being defined +# COND: the Conditional under which it is being defined +# CONDSET: the ConditionalSet under which it had already been defined +sub conditional_ambiguous_p ($$$) { - my ($var, $cond, @conds) = @_; + my ($var, $cond, $condset) = @_; - foreach my $vcond (@conds) + foreach my $vcond ($condset->conds) { # Note that these rules doesn't consider the following # example as ambiguous. @@ -6194,10 +6177,10 @@ sub variable_not_always_defined_in_cond ($$) # COND1_TRUE. This yields an empty list and we are done. my @res = (); - my @cond_defs = variable_conditions ($var); # (1) - foreach my $icond (invert_conditions (@cond_defs)) # (2) + my $cond_defs = variable_conditions ($var); # (1) + foreach my $icond ($cond_defs->invert->conds) # (2) { - prog_error "invert_conditions returned an input condition" + prog_error "->invert returned an input condition" if exists $var_value{$var}{$icond}; push @res, $icond @@ -6284,7 +6267,7 @@ sub macro_define ($$$$$$) $var_value{$var}{$cond} .= $value; } # 2. append (+=) to a variable defined for *another* condition - elsif ($type eq '+' && variable_conditions ($var)) + elsif ($type eq '+' && ! variable_conditions ($var)->false) { # * Generally, $cond is not TRUE. For instance: # FOO = foo @@ -6335,7 +6318,7 @@ sub macro_define ($$$$$$) } # Add VALUE to all definitions of VAR. - foreach my $vcond (variable_conditions ($var)) + foreach my $vcond (variable_conditions ($var)->conds) { # We have a bit of error detection to do here. # This: @@ -6463,7 +6446,7 @@ sub macro_dump ($) else { $text .= " $var $var_type{$var}=\n {\n"; - foreach my $vcond (variable_sorted_conditions ($var)) + foreach my $vcond (variable_conditions ($var)->conds) { prog_error ("`$var' is a key in \$var_value, " . "but not in \$var_owner\n") @@ -6550,7 +6533,7 @@ sub variable_defined ($;$) if (exists $targets{$var} && (! defined $cond || exists $targets{$var}{$cond})) { - for my $tcond ($cond || target_conditions ($var)) + for my $tcond ($cond || ! target_conditions ($var)->false) { prog_error ("\$targets{$var}{$tcond} exists but " . "\$target_owner doesn't") @@ -6630,21 +6613,7 @@ sub variable_conditions_recursive ($) # Now we want to return all permutations of the subvariable # conditions. - my %allconds = (); - foreach my $item (@new_conds) - { - foreach ($item->conds) - { - s/^(.*)_(TRUE|FALSE)$/$1_TRUE/; - $allconds{$_} = 1; - } - } - @new_conds = variable_conditions_permutations (sort keys %allconds); - - # Note we cannot just do `return sort @new_conds', because this - # function is sometimes used in a scalar context. - my @uniq_list = sort by_condition @new_conds; - return @uniq_list; + return (new Automake::ConditionalSet @new_conds)->permutations; } @@ -6658,18 +6627,8 @@ sub variable_conditions_recursive ($) sub variable_conditions ($) { my ($var) = @_; - return keys %{$var_value{$var}}; -} - - -# @CONDS -# variable_sorted_conditions ($VAR) -# --------------------------------- -# Same as &variable_conditions, but return a sorted list. -sub variable_sorted_conditions ($) -{ - my ($var) = @_; - return sort by_condition variable_conditions $var; + my @conds = keys %{$var_value{$var}}; + return new Automake::ConditionalSet @conds; } @@ -6680,7 +6639,8 @@ sub variable_sorted_conditions ($) sub target_conditions ($) { my ($target) = @_; - return keys %{$targets{$target}}; + my @conds = keys %{$targets{$target}}; + return new Automake::ConditionalSet @conds; } # $BOOLEAN @@ -6689,7 +6649,7 @@ sub target_conditions ($) sub variable_conditionally_defined ($) { my ($var) = @_; - foreach my $cond (variable_conditions_recursive ($var)) + foreach my $cond (variable_conditions_recursive ($var)->conds) { return 1 unless $cond =~ /^TRUE|FALSE$/; @@ -6766,7 +6726,7 @@ sub variable_conditions_recursive_sub my @this_conds = (); # Examine every condition under which $VAR is defined. - foreach my $vcond (variable_conditions ($var)) + foreach my $vcond (variable_conditions ($var)->conds) { push (@this_conds, $vcond); @@ -6815,8 +6775,8 @@ sub variable_conditions_recursive_sub # in @this_conds. foreach my $this_cond (@this_conds) { - my @perms = - variable_conditions_permutations ($this_cond->conds); + my @perms = + (new Automake::ConditionalSet $this_cond)->permutations->conds; foreach my $perm (@perms) { my $ok = 1; @@ -6840,80 +6800,6 @@ sub variable_conditions_recursive_sub } -# @CONDS -# invert_conditions (@CONDS) -# -------------------------- -# Invert a list of conditionals. Returns a set of conditionals which -# are never true for any of the input conditionals, and when taken -# together with the input conditionals cover all possible cases. -# -# For example: -# invert_conditions("A_TRUE B_TRUE", "A_FALSE B_FALSE") -# => ("A_FALSE B_TRUE", "A_TRUE B_FALSE") -# -# invert_conditions("A_TRUE B_TRUE", "A_TRUE B_FALSE", "A_FALSE") -# => () -sub invert_conditions -{ - my (@conds) = @_; - - my @notconds = (); - - # Generate all permutation for all inputs. - my @perm = map { variable_conditions_permutations ($_->conds); } @conds; - # Remove redundant conditions. - @perm = Automake::Conditional::reduce @perm; - - # Now remove all conditions which imply one of the input conditions. - foreach my $perm (@perm) - { - push @notconds, $perm - if ! $perm->implies_any (@conds); - } - return @notconds; -} - -# Return a list of permutations of a conditional string. -# (But never output FALSE conditions, they are useless.) -# -# Examples: -# variable_conditions_permutations ("FOO_FALSE", "BAR_TRUE") -# => ("FOO_FALSE BAR_FALSE", -# "FOO_FALSE BAR_TRUE", -# "FOO_TRUE BAR_FALSE", -# "FOO_TRUE BAR_TRUE") -# variable_conditions_permutations ("FOO_FALSE", "TRUE") -# => ("FOO_FALSE TRUE", -# "FOO_TRUE TRUE") -# variable_conditions_permutations ("TRUE") -# => ("TRUE") -# variable_conditions_permutations ("FALSE") -# => ("TRUE") -sub variable_conditions_permutations -{ - my (@comps) = @_; - return () - if ! @comps; - my $comp = shift (@comps); - return variable_conditions_permutations (@comps) - if $comp eq ''; - my $neg = condition_negate ($comp); - - my @ret; - foreach my $sub (variable_conditions_permutations (@comps)) - { - push (@ret, $sub->merge_conds ($comp)) if $comp ne 'FALSE'; - push (@ret, $sub->merge_conds ($neg)) if $neg ne 'FALSE'; - } - if (! @ret) - { - push (@ret, new Automake::Conditional $comp) if $comp ne 'FALSE'; - push (@ret, new Automake::Conditional $neg) if $neg ne 'FALSE'; - } - return @ret; -} - - # $BOOL # &check_variable_defined_unconditionally($VAR, $PARENT) # ------------------------------------------------------ @@ -6922,7 +6808,7 @@ sub variable_conditions_permutations sub check_variable_defined_unconditionally ($$) { my ($var, $parent) = @_; - foreach my $cond (variable_conditions ($var)) + foreach my $cond (variable_conditions ($var)->conds) { next if $cond->true || $cond->false; @@ -7058,7 +6944,7 @@ sub variable_value_as_list # Get value for given condition my $onceflag; - foreach my $vcond (variable_conditions ($var)) + foreach my $vcond (variable_conditions ($var)->conds) { my $val = $var_value{$var}{$vcond}; @@ -7117,7 +7003,7 @@ sub variable_value_as_list_recursive_worker ($$$$) elsif ($cond eq 'all') { $vars_scanned{$var} = 1; - foreach my $vcond (variable_conditions ($var)) + foreach my $vcond (variable_conditions ($var)->conds) { push (@result, &value_to_list ($var, $var_value{$var}{$vcond}, @@ -7130,7 +7016,7 @@ sub variable_value_as_list_recursive_worker ($$$$) { $vars_scanned{$var} = 1; my $onceflag; - foreach my $vcond (variable_conditions ($var)) + foreach my $vcond (variable_conditions ($var)->conds) { my $val = $var_value{$var}{$vcond}; my $where = $var_location{$var}{$vcond}; @@ -7163,7 +7049,7 @@ sub variable_output ($@) { my ($var, @conds) = @_; - @conds = variable_sorted_conditions $var + @conds = variable_conditions ($var)->conds unless @conds; foreach my $cond (@conds) @@ -7194,7 +7080,7 @@ sub variable_pretty_output ($@) { my ($var, @conds) = @_; - @conds = variable_sorted_conditions $var + @conds = variable_conditions ($var)->conds unless @conds; foreach my $cond (@conds) @@ -7582,9 +7468,9 @@ sub rule_define ($$$$$) # was already defined in condition COND1 and we want to define # it in condition TRUE, then define it only in condition !COND1. # (See cond14.test and cond15.test for some test cases.) - my @defined_conds = target_conditions ($target); + my $defined_conds = target_conditions ($target); @conds = (); - for my $undefined_cond (invert_conditions(@defined_conds)) + for my $undefined_cond ($defined_conds->invert->conds) { push @conds, $cond->merge ($undefined_cond); } @@ -8358,7 +8244,7 @@ sub append_exeext ($) prog_error "append_exeext ($macro)" unless $macro =~ /_PROGRAMS$/; - my @conds = variable_conditions_recursive ($macro); + my @conds = variable_conditions_recursive ($macro)->conds; my @condvals; foreach my $cond (@conds) @@ -8386,7 +8272,7 @@ sub append_exeext ($) # FIXME: Currently it's a bit hard to chose a condition becose the # set of input condition is different from the set of ouput # conditions. See also PR/352. So we just pick the first one. - my $cond = (variable_conditions ($macro))[0]; + my $cond = variable_conditions ($macro)->one_cond; my $where = $var_location{$macro}{$cond}; macro_delete ($macro); @@ -8565,7 +8451,7 @@ sub am_install_var # Use the location of the currently processed variable. # We are not processing a particular condition, so pick the first # available. - my $tmpcond = (variable_conditions ($one_name))[0]; + my $tmpcond = variable_conditions ($one_name)->one_cond; my $where = $var_location{$one_name}{$tmpcond}->clone; # Append actual contents of where_PRIMARY variable to @@ -9115,7 +9001,7 @@ sub require_variables ($$$@) sub require_variables_for_macro ($$@) { my ($macro, $reason, @args) = @_; - for my $cond (variable_conditions ($macro)) + for my $cond (variable_conditions ($macro)->conds) { return require_variables ($var_location{$macro}{$cond}, $reason, $cond, @args); diff --git a/lib/Automake/Conditional.pm b/lib/Automake/Conditional.pm index 31e02515..cbef6b45 100644 --- a/lib/Automake/Conditional.pm +++ b/lib/Automake/Conditional.pm @@ -99,7 +99,7 @@ the following statement. Remember that a C is a I of conditions, so the above C means C is defined when C is true B C are true. There is no way to express disjunctions -(i.e., Is) with this class. +(i.e., Is) with this class (see L). Another point worth to mention is that each C object is unique with respect to its conditions. Two C objects @@ -443,6 +443,10 @@ sub reduce (@) return @ret; } +=head1 SEE ALSO + +L. + =head1 HISTORY Cs and supporting code were added to Automake 1.1o by diff --git a/lib/Automake/ConditionalSet.pm b/lib/Automake/ConditionalSet.pm new file mode 100644 index 00000000..91a93e7d --- /dev/null +++ b/lib/Automake/ConditionalSet.pm @@ -0,0 +1,416 @@ +package Automake::ConditionalSet; + +use Carp; +use strict; +use Automake::Conditional; + +=head1 NAME + +Automake::ConditionalSet - record a disjunction of conditions + +=head1 SYNOPSIS + + use Automake::Conditional; + use Automake::ConditionalSet; + + # Create a conditional to represent "COND1 and not COND2". + my $cond = new Automake::Conditional "COND1_TRUE", "COND2_FALSE"; + # Create a conditional to represent "not COND3". + my $other = new Automake::Conditional "COND3_FALSE"; + + # Create a ConditionalSet to represent + # "(COND1 and not COND2) or (not COND3)" + my $set = new Automake::ConditionalSet $cond, $other; + + # Return the list of Conditionals involved in $set. + my @conds = $set->conds; + + # Return one of the Conditional involved in $set. + my $cond = $set->one_cond; + + # Return true iff $set is always true (i.e. its subconditions + # conver all cases). + if ($set->true) { ... } + + # Return false iff $set is always false (i.e. is empty, or contains + # only false conditions). + if ($set->false) { ... } + + # Return a string representing the ConditionalSet. + my $str = $set->string; + + # Build a new ConditionalSet from the permuation of all + # subconditions appearing in $set. + my $perm = $set->permutations; + + # Invert a ConditionalSet, i.e., create a new ConditionalSet + # that complements $set. + my $inv = $set->invert; + +=head1 DESCRIPTION + +A C is a disjunction of atomic conditions. In +Automake they are used to represent the conditions into which Makefile +variables and Makefile rules are defined. + +If the variable C is defined as + + if COND1 + if COND2 + VAR = value1 + endif + endif + if !COND3 + if COND4 + VAR = value2 + endif + endif + +then it will be associated a C created with +the following statement. + + new Automake::ConditionalSet + (new Automake::Conditional ("COND1_TRUE", "COND2_TRUE"), + new Automake::Conditional ("COND3_FALSE", "COND4_TRUE")); + +As you can see, a C is made from a list of +Cs. Since C is a disjunction, and +C is a conjunction, the above can be read as +follows. + + (COND1 and COND2) or ((not COND3) and COND4) + +Like C objects, a C object is unisque +with respect to its conditions. Two C objects created +for the same set of conditions will have the same adress. This makes +it easy to compare Cs: just compare the references. + +=head2 Methods + +=over 4 + +=item C<$set = new Automake::ConditionalSet [@conds]> + +Create a C object from the list of C +objects passed in arguments. + +If the C<@conds> list is empty, the C is assumed to be +false. + +As explained previously, the reference (object) returned is unique +with respect to C<@conds>. For this purpose, duplicate elements are +ignored, and C<@conds> is rewriten as C<("TRUE")> if it contains +C<"TRUE">. + +=cut + +# Keys in this hash are ConditionalSet strings. Values are the +# associated object ConditionalSet. This is used by `new' to reuse +# ConditionalSet objects with identical conditions. +use vars '%_conditional_set_singletons'; + +sub new ($;@) +{ + my ($class, @conds) = @_; + my $self = { + hash => {}, + }; + bless $self, $class; + + for my $cond (@conds) + { + confess "`$cond' isn't a reference" unless ref $cond; + confess "`$cond' isn't an Automake::Conditional" + unless $cond->isa ("Automake::Conditional"); + + # This is a disjunction of conditions, so we drop + # false conditions. We'll always treat an "empty" + # ConditionalSet as false for this reason. + next if $cond->false; + + # If we see true, then the whole set is true! + if ($cond->true && $#conds > 0) + { + return new Automake::ConditionalSet $cond; + } + + # Store conditions as keys AND as values, because blessed + # objects are converted to string when used as keys (so + # at least we still have the value when we need to call + # a method). + $self->{'hash'}{$cond} = $cond; + } + + my $key = $self->string; + if (exists $_conditional_set_singletons{$key}) + { + return $_conditional_set_singletons{$key}; + } + $_conditional_set_singletons{$key} = $self; + return $self; +} + +# Compare condition names. +# Issue them in alphabetical order, foo_TRUE before foo_FALSE. +sub by_condition +{ + # Be careful we might be comparing `' or `#'. + $a->string =~ /^(.*)_(TRUE|FALSE)$/; + my ($aname, $abool) = ($1 || '', $2 || ''); + $b->string =~ /^(.*)_(TRUE|FALSE)$/; + my ($bname, $bbool) = ($1 || '', $2 || ''); + return ($aname cmp $bname + # Don't bother with IFs, given that TRUE is after FALSE + # just cmp in the reverse order. + || $bbool cmp $abool + # Just in case... + || $a cmp $b); +} + +=item C<@conds = $set-$conds> + +Return the list of C objects involved in C<$set>. + +=cut + +sub conds ($ ) +{ + my ($self) = @_; + return @{$self->{'conds'}} if exists $self->{'conds'}; + my @conds = map { $self->{'hash'}{$_} } (keys %{$self->{'hash'}}); + $self->{'conds'} = [sort by_condition @conds]; + return @conds; +} + +=item C<$cond = $set-$one_cond> + +Return one C object involved in C<$set>. + +=cut + +sub one_cond ($) +{ + my ($self) = @_; + return (%{$self->{'hash'}},)[1]; +} + +=item C<$et = $set-$false> + +Return 1 iff the C object is always false (i.e., if it +is empty, or if it contains only false Cs). Return 0 +otherwise. + +=cut + +sub false ($ ) +{ + my ($self) = @_; + return 0 == keys %{$self->{'hash'}}; +} + +=item C<$et = $set-$true> + +Return 1 iff the C object is always true (i.e. covers all +conditions). Return 0 otherwise. + +=cut + +sub true ($ ) +{ + my ($self) = @_; + # To know whether a ConditionalSet covers all + # we invert it. invert() will set $self->{'true'}. + $self->invert unless exists $self->{'true'}; + return $self->{'true'}; +} + +=item C<$str = $set-Estring> + +Build a string which denotes the C. + +=cut + +sub string ($ ) +{ + my ($self) = @_; + + return $self->{'string'} if defined $self->{'string'}; + + my $res = ''; + if ($self->false) + { + $res = 'FALSE'; + } + else + { + $res = join (',', $self->conds); + } + + $self->{'string'} = $res; + return $res; +} + + +sub _permutations_worker (@) +{ + my @conds = @_; + return () unless @conds; + + my $cond = shift @conds; + (my $neg = $cond) =~ s/TRUE$/FALSE/; + + # Recurse. + + # Don't merge `FALSE' conditions, since this will just create + # a false Conditional, and we'll drop them later in ConditionalSet. + # (Dropping them now limits the combinatoric explosion.) + my @ret = (); + foreach my $c (&_permutations_worker (@conds)) + { + push (@ret, $c->merge_conds ($cond)); + push (@ret, $c->merge_conds ($neg)) if $neg ne 'FALSE'; + } + if (! @ret) + { + push (@ret, new Automake::Conditional $cond); + push (@ret, new Automake::Conditional $neg) if $neg ne 'FALSE'; + } + + return @ret; +} + +=item C<$perm = $set-Epermutations> + +Return a permutations of the subconditions involved in a C. + +For instance consider this initial C. + + my $set = new Automake::ConditionalSet + (new Automake::Conditional ("COND1_TRUE", "COND2_TRUE"), + new Automake::Conditional ("COND3_FALSE", "COND2_TRUE")); + +Calling $<$set-Epermutations> will return the following Conditional set. + + new Automake::ConditionalSet + (new Automake::Conditional ("COND1_TRUE", "COND2_TRUE", "COND2_TRUE"), + new Automake::Conditional ("COND1_FALSE","COND2_TRUE", "COND2_TRUE"), + new Automake::Conditional ("COND1_TRUE", "COND2_FALSE","COND2_TRUE"), + new Automake::Conditional ("COND1_FALSE","COND2_FALSE","COND2_TRUE"), + new Automake::Conditional ("COND1_TRUE", "COND2_TRUE", "COND2_FALSE"), + new Automake::Conditional ("COND1_FALSE","COND2_TRUE", "COND2_FALSE"), + new Automake::Conditional ("COND1_TRUE", "COND2_FALSE","COND2_FALSE"), + new Automake::Conditional ("COND1_FALSE","COND2_FALSE","COND2_FALSE")); + +=cut + +sub permutations ($ ) +{ + my ($self) = @_; + + return $self->{'permutations'} if defined $self->{'permutations'}; + + my %atomic_conds = (); + + for my $conditional ($self->conds) + { + for my $cond ($conditional->conds) + { + $cond =~ s/FALSE$/TRUE/; + $atomic_conds{$cond} = 1; + } + } + + my @res = _permutations_worker (keys %atomic_conds); + my $res = new Automake::ConditionalSet @res; + + $self->{'permutations'} = $res; + + return $res; +} + +=item C<$inv = $res-Einvert> + +Invert a C. Return a C which is true +when C<$res> is false, and vice-versa. + + my $set = new Automake::ConditionalSet + (new Automake::Conditional ("A_TRUE", "B_TRUE"), + new Automake::Conditional ("A_FALSE", "B_FALSE")); + +Calling C<$set-Einvert> will return the following C. + + new Automake::ConditionalSet + (new Automake::Conditional ("A_TRUE", "B_FALSE"), + new Automake::Conditional ("A_FALSE", "B_TRUE")); + +=cut + +sub invert($ ) +{ + my ($self) = @_; + + return $self->{'invert'} if defined $self->{'invert'}; + + # Generate permutations for all subconditions. + my @perm = $self->permutations->conds; + # Remove redundant conditions. + @perm = Automake::Conditional::reduce @perm; + + # Now remove all conditions which imply one of the input conditions. + my @conds = $self->conds; + my @notconds = (); + foreach my $perm (@perm) + { + push @notconds, $perm + if ! $perm->implies_any (@conds); + } + + my $res = new Automake::ConditionalSet @notconds; + + # Cache result. + $self->{'invert'} = $res; + # It's tempting to also set $res->{'invert'} to $self, but that + # isn't a bad idea as $self hasn't been normalized in any way. + # (Different inputs can produce the same inverted set.) + + # If $res is false, then $self covers all cases. The true() + # method relies on this function to figure that. + $self->{'true'} = $res->false; + + return $res; +} + +=head1 SEE ALSO + +L. + +=head1 HISTORY + +Cs and supporting code were added to Automake 1.1o by +Ian Lance Taylor in 1997. Since then it has been +improved by Tom Tromey , Richard Boulton +, Raja R Harinath , Akim +Demaille , and Pavel Roskin . +Alexandre Duret-Lutz extracted the code out of Automake +to create this package in 2002. + +=cut + +1; + +### Setup "GNU" style for perl-mode and cperl-mode. +## Local Variables: +## perl-indent-level: 2 +## perl-continued-statement-offset: 2 +## perl-continued-brace-offset: 0 +## perl-brace-offset: 0 +## perl-brace-imaginary-offset: 0 +## perl-label-offset: -2 +## cperl-indent-level: 2 +## cperl-brace-offset: 0 +## cperl-continued-brace-offset: 0 +## cperl-label-offset: -2 +## cperl-extra-newline-before-brace: t +## cperl-merge-trailing-else: nil +## cperl-continued-statement-offset: 2 +## End: diff --git a/lib/Automake/Makefile.am b/lib/Automake/Makefile.am index 93c32c3f..c196a132 100644 --- a/lib/Automake/Makefile.am +++ b/lib/Automake/Makefile.am @@ -4,6 +4,7 @@ perllibdir = $(pkgvdatadir)/Automake dist_perllib_DATA = \ Channels.pm \ Conditional.pm \ + ConditionalSet.pm \ General.pm \ Location.pm \ Struct.pm \ diff --git a/lib/Automake/Makefile.in b/lib/Automake/Makefile.in index 49f90555..5e987469 100644 --- a/lib/Automake/Makefile.in +++ b/lib/Automake/Makefile.in @@ -96,6 +96,7 @@ perllibdir = $(pkgvdatadir)/Automake dist_perllib_DATA = \ Channels.pm \ Conditional.pm \ + ConditionalSet.pm \ General.pm \ Location.pm \ Struct.pm \ -- 2.43.5