automake-patches
[Top][All Lists]
Advanced

[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





reply via email to

[Prev in Thread] Current Thread [Next in Thread]