[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
FYI: ConditionalSet.pm
From: |
Alexandre Duret-Lutz |
Subject: |
FYI: ConditionalSet.pm |
Date: |
Thu, 14 Nov 2002 17:09:37 +0100 |
User-agent: |
Gnus/5.090008 (Oort Gnus v0.08) Emacs/20.7 (i386-debian-linux-gnu) |
I'm checking this in.
2002-11-14 Alexandre Duret-Lutz <address@hidden>
* 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.
Index: automake.in
===================================================================
RCS file: /cvs/automake/automake/automake.in,v
retrieving revision 1.1385
diff -u -r1.1385 automake.in
--- automake.in 13 Nov 2002 21:58:26 -0000 1.1385
+++ automake.in 14 Nov 2002 16:01:55 -0000
@@ -117,6 +117,7 @@
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 @@
{
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 @@
{
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 @@
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 @@
# 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 @@
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 @@
}
-# 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 @@
}
# $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 @@
# 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 @@
$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 @@
}
# 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 @@
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 @@
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 @@
# 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 ($)
{
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 target_conditions ($)
{
my ($target) = @_;
- return keys %{$targets{$target}};
+ my @conds = keys %{$targets{$target}};
+ return new Automake::ConditionalSet @conds;
}
# $BOOLEAN
@@ -6689,7 +6649,7 @@
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 @@
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 @@
# 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 @@
}
-# @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 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 @@
# 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 @@
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 @@
{
$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 @@
{
my ($var, @conds) = @_;
- @conds = variable_sorted_conditions $var
+ @conds = variable_conditions ($var)->conds
unless @conds;
foreach my $cond (@conds)
@@ -7194,7 +7080,7 @@
{
my ($var, @conds) = @_;
- @conds = variable_sorted_conditions $var
+ @conds = variable_conditions ($var)->conds
unless @conds;
foreach my $cond (@conds)
@@ -7582,9 +7468,9 @@
# 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 @@
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 @@
# 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 @@
# 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_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);
Index: lib/Automake/Conditional.pm
===================================================================
RCS file: /cvs/automake/automake/lib/Automake/Conditional.pm,v
retrieving revision 1.3
diff -u -r1.3 Conditional.pm
--- lib/Automake/Conditional.pm 13 Nov 2002 20:11:32 -0000 1.3
+++ lib/Automake/Conditional.pm 14 Nov 2002 16:01:56 -0000
@@ -99,7 +99,7 @@
Remember that a C<Conditional> is a I<conjunction> of conditions, so
the above C<Conditional> means C<VAR> is defined when C<COND1> is true
B<and> C<COND2> are true. There is no way to express disjunctions
-(i.e., I<or>s) with this class.
+(i.e., I<or>s) with this class (see L<ConditionalSet>).
Another point worth to mention is that each C<Conditional> object is
unique with respect to its conditions. Two C<Conditional> objects
@@ -442,6 +442,10 @@
return TRUE if @ret == 0;
return @ret;
}
+
+=head1 SEE ALSO
+
+L<Automake::ConditionalSet>.
=head1 HISTORY
Index: lib/Automake/ConditionalSet.pm
===================================================================
RCS file: lib/Automake/ConditionalSet.pm
diff -N lib/Automake/ConditionalSet.pm
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ lib/Automake/ConditionalSet.pm 14 Nov 2002 16:01:58 -0000
@@ -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<ConditionalSet> 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<VAR> 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<ConditionalSet> 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<ConditionalSet> is made from a list of
+C<Conditional>s. Since C<ConditionalSet> is a disjunction, and
+C<Conditional> is a conjunction, the above can be read as
+follows.
+
+ (COND1 and COND2) or ((not COND3) and COND4)
+
+Like C<Conditional> objects, a C<ConditionalSet> object is unisque
+with respect to its conditions. Two C<ConditionalSet> objects created
+for the same set of conditions will have the same adress. This makes
+it easy to compare C<ConditionalSet>s: just compare the references.
+
+=head2 Methods
+
+=over 4
+
+=item C<$set = new Automake::ConditionalSet address@hidden>
+
+Create a C<ConditionalSet> object from the list of C<Conditional>
+objects passed in arguments.
+
+If the C<@conds> list is empty, the C<ConditionalSet> 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-$<gt>conds>
+
+Return the list of C<Conditional> 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-$<gt>one_cond>
+
+Return one C<Conditional> object involved in C<$set>.
+
+=cut
+
+sub one_cond ($)
+{
+ my ($self) = @_;
+ return (%{$self->{'hash'}},)[1];
+}
+
+=item C<$et = $set-$<gt>false>
+
+Return 1 iff the C<ConditionalSet> object is always false (i.e., if it
+is empty, or if it contains only false C<Conditional>s). Return 0
+otherwise.
+
+=cut
+
+sub false ($ )
+{
+ my ($self) = @_;
+ return 0 == keys %{$self->{'hash'}};
+}
+
+=item C<$et = $set-$<gt>true>
+
+Return 1 iff the C<ConditionalSet> 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-E<gt>string>
+
+Build a string which denotes the C<ConditionalSet>.
+
+=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-E<gt>permutations>
+
+Return a permutations of the subconditions involved in a C<ConditionalSet>.
+
+For instance consider this initial C<ConditionalSet>.
+
+ my $set = new Automake::ConditionalSet
+ (new Automake::Conditional ("COND1_TRUE", "COND2_TRUE"),
+ new Automake::Conditional ("COND3_FALSE", "COND2_TRUE"));
+
+Calling $<$set-E<gt>permutations> 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-E<gt>invert>
+
+Invert a C<ConditionalSet>. Return a C<ConditionalSet> 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-E<gt>invert> will return the following C<ConditionalSet>.
+
+ 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<Automake::Conditional>.
+
+=head1 HISTORY
+
+C<AM_CONDITIONAL>s and supporting code were added to Automake 1.1o by
+Ian Lance Taylor <address@hidden> in 1997. Since then it has been
+improved by Tom Tromey <address@hidden>, Richard Boulton
+<address@hidden>, Raja R Harinath <address@hidden>, Akim
+Demaille <address@hidden>, and Pavel Roskin <address@hidden>.
+Alexandre Duret-Lutz <address@hidden> 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:
Index: lib/Automake/Makefile.am
===================================================================
RCS file: /cvs/automake/automake/lib/Automake/Makefile.am,v
retrieving revision 1.6
diff -u -r1.6 Makefile.am
--- lib/Automake/Makefile.am 7 Oct 2002 09:23:32 -0000 1.6
+++ lib/Automake/Makefile.am 14 Nov 2002 16:01:58 -0000
@@ -4,6 +4,7 @@
dist_perllib_DATA = \
Channels.pm \
Conditional.pm \
+ ConditionalSet.pm \
General.pm \
Location.pm \
Struct.pm \
Index: lib/Automake/Makefile.in
===================================================================
RCS file: /cvs/automake/automake/lib/Automake/Makefile.in,v
retrieving revision 1.53
diff -u -r1.53 Makefile.in
--- lib/Automake/Makefile.in 7 Oct 2002 09:23:32 -0000 1.53
+++ lib/Automake/Makefile.in 14 Nov 2002 16:01:58 -0000
@@ -96,6 +96,7 @@
dist_perllib_DATA = \
Channels.pm \
Conditional.pm \
+ ConditionalSet.pm \
General.pm \
Location.pm \
Struct.pm \
--
Alexandre Duret-Lutz