Browse Source

ENH: support parenthesis as arguments and in conditionals feature request #6191

Ken Martin 17 năm trước cách đây
mục cha
commit
19e891532a

+ 277 - 222
Source/cmIfCommand.cxx

@@ -21,8 +21,10 @@
 #include <list>
 #include <cmsys/RegularExpression.hxx>
 
+//=========================================================================
 bool cmIfFunctionBlocker::
-IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
+IsFunctionBlocked(const cmListFileFunction& lff, 
+                  cmMakefile &mf,
                   cmExecutionStatus &inStatus)
 {
   // Prevent recusion and don't let this blocker block its own
@@ -140,6 +142,7 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
   return true;
 }
 
+//=========================================================================
 bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
                                        cmMakefile&)
 {
@@ -157,8 +160,8 @@ bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
   return false;
 }
 
-void cmIfFunctionBlocker::
-ScopeEnded(cmMakefile &mf)
+//=========================================================================
+void cmIfFunctionBlocker::ScopeEnded(cmMakefile &mf)
 {
   std::string errmsg = "The end of a CMakeLists file was reached with an "
     "IF statement that was not closed properly.\nWithin the directory: ";
@@ -175,6 +178,7 @@ ScopeEnded(cmMakefile &mf)
   cmSystemTools::Message(errmsg.c_str(), "Warning");
 }
 
+//=========================================================================
 bool cmIfCommand
 ::InvokeInitialPass(const std::vector<cmListFileArgument>& args, 
                     cmExecutionStatus &)
@@ -221,6 +225,7 @@ bool cmIfCommand
 
 namespace 
 {
+//=========================================================================
   void IncrementArguments(std::list<std::string> &newArgs,
                           std::list<std::string>::iterator &argP1,
                           std::list<std::string>::iterator &argP2)
@@ -235,68 +240,108 @@ namespace
         }
       }
   }
-}
-
-
-// order of operations, 
-// IS_DIRECTORY EXISTS COMMAND DEFINED 
-// MATCHES LESS GREATER EQUAL STRLESS STRGREATER STREQUAL 
-// AND OR
-//
-// There is an issue on whether the arguments should be values of references,
-// for example IF (FOO AND BAR) should that compare the strings FOO and BAR
-// or should it really do IF (${FOO} AND ${BAR}) Currently IS_DIRECTORY
-// EXISTS COMMAND and DEFINED all take values. EQUAL, LESS and GREATER can
-// take numeric values or variable names. STRLESS and STRGREATER take
-// variable names but if the variable name is not found it will use the name
-// directly. AND OR take variables or the values 0 or 1.
-
 
-bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
-                         char **errorString, cmMakefile *makefile)
-{
-  // check for the different signatures
-  const char *def;
-  const char *def2;
-  const char* msg = "Unknown arguments specified";
-  *errorString = new char[strlen(msg) + 1];
-  strcpy(*errorString, msg);
+  //=========================================================================
+  // helper function to reduce code duplication
+  void HandlePredicate(bool value, int &reducible,
+                       std::list<std::string>::iterator &arg,
+                       std::list<std::string> &newArgs,
+                       std::list<std::string>::iterator &argP1,
+                       std::list<std::string>::iterator &argP2)
+  {
+    if(value)
+      {
+      *arg = "1";
+      }
+    else 
+      {
+      *arg = "0";
+      }
+    newArgs.erase(argP1);
+    argP1 = arg;
+    IncrementArguments(newArgs,argP1,argP2);
+    reducible = 1;
+  }
 
-  // handle empty invocation
-  if (args.size() < 1)
-    {
-    delete [] *errorString;
-    *errorString = 0;
-    return false;
-    }
+  //=========================================================================
+  // helper function to reduce code duplication
+  void HandleBinaryOp(bool value, int &reducible,
+                       std::list<std::string>::iterator &arg,
+                       std::list<std::string> &newArgs,
+                       std::list<std::string>::iterator &argP1,
+                       std::list<std::string>::iterator &argP2)
+  {
+    if(value)
+      {
+      *arg = "1";
+      }
+    else 
+      {
+      *arg = "0";
+      }
+    newArgs.erase(argP2);
+    newArgs.erase(argP1);
+    argP1 = arg;
+    IncrementArguments(newArgs,argP1,argP2);
+    reducible = 1;
+  }
 
-  // store the reduced args in this vector
-  std::list<std::string> newArgs;
+  //=========================================================================
+  // level 0 processes parenthetical expressions
+  bool HandleLevel0(std::list<std::string> &newArgs,
+                    cmMakefile *makefile,
+                    char **errorString)
+  {
   int reducible;
-  unsigned int i;
-
-  // copy to the list structure
-  for(i = 0; i < args.size(); ++i)
-    {   
-    newArgs.push_back(args[i]);
-    }
-  std::list<std::string>::iterator argP1;
-  std::list<std::string>::iterator argP2;
-
-  // now loop through the arguments and see if we can reduce any of them
-  // we do this multiple times. Once for each level of precedence
   do
     {
     reducible = 0;
     std::list<std::string>::iterator arg = newArgs.begin();
     while (arg != newArgs.end())
       {
-      argP1 = arg;
-      IncrementArguments(newArgs,argP1,argP2);
-      // does a file exist
-      if (*arg == "EXISTS" && argP1  != newArgs.end())
+      if (*arg == "(")
         {
-        if(cmSystemTools::FileExists((argP1)->c_str()))
+        // search for the closing paren for this opening one
+        std::list<std::string>::iterator argClose;
+        argClose = arg;
+        argClose++;
+        unsigned int depth = 1;
+        while (argClose != newArgs.end() && depth)
+          {
+          if (*argClose == "(")
+            {
+              depth++;
+            }
+          if (*argClose == ")")
+            {
+              depth--;
+            }
+          argClose++;
+          }
+        if (depth)
+          {
+          cmOStringStream error;
+          error << "mismatched parenthesis in condition";
+          delete [] *errorString;
+          *errorString = new char[error.str().size() + 1];
+          strcpy(*errorString, error.str().c_str());
+          return false;
+          }
+        // store the reduced args in this vector
+        std::vector<std::string> newArgs2;
+
+        // copy to the list structure
+        std::list<std::string>::iterator argP1 = arg;
+        argP1++;
+        for(; argP1 != argClose; argP1++)
+          {   
+          newArgs2.push_back(*argP1);
+          }
+        newArgs2.pop_back();
+        // now recursively invoke IsTrue to handle the values inside the parenthetical expression
+        bool value = 
+          cmIfCommand::IsTrue(newArgs2, errorString, makefile);
+        if(value)
           {
           *arg = "1";
           }
@@ -304,75 +349,70 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
           {
           *arg = "0";
           }
-        newArgs.erase(argP1);
         argP1 = arg;
-        IncrementArguments(newArgs,argP1,argP2);
-        reducible = 1;
+        argP1++;
+        // remove the now evaluated parenthetical expression
+        newArgs.erase(argP1,argClose);        
+        }
+      ++arg;
+      }
+    }
+  while (reducible);
+  return true;
+  }
+  
+  //=========================================================================
+  // level one handles most predicates except for NOT
+  bool HandleLevel1(std::list<std::string> &newArgs,
+                    cmMakefile *makefile,
+                    char **)
+  {
+  int reducible;
+  do
+    {
+    reducible = 0;
+    std::list<std::string>::iterator arg = newArgs.begin();
+    std::list<std::string>::iterator argP1;
+    std::list<std::string>::iterator argP2;
+    while (arg != newArgs.end())
+      {
+      argP1 = arg;
+      IncrementArguments(newArgs,argP1,argP2);
+      // does a file exist
+      if (*arg == "EXISTS" && argP1  != newArgs.end())
+        {
+        HandlePredicate(
+          cmSystemTools::FileExists((argP1)->c_str()),
+          reducible, arg, newArgs, argP1, argP2);
         }
       // does a directory with this name exist
       if (*arg == "IS_DIRECTORY" && argP1  != newArgs.end())
         {
-        if(cmSystemTools::FileIsDirectory((argP1)->c_str()))
-          {
-          *arg = "1";
-          }
-        else 
-          {
-          *arg = "0";
-          }
-        newArgs.erase(argP1);
-        argP1 = arg;
-        IncrementArguments(newArgs,argP1,argP2);
-        reducible = 1;
+        HandlePredicate(
+          cmSystemTools::FileIsDirectory((argP1)->c_str()),
+          reducible, arg, newArgs, argP1, argP2);
         }
       // is the given path an absolute path ?
       if (*arg == "IS_ABSOLUTE" && argP1  != newArgs.end())
         {
-        if(cmSystemTools::FileIsFullPath((argP1)->c_str()))
-          {
-          *arg = "1";
-          }
-        else 
-          {
-          *arg = "0";
-          }
-        newArgs.erase(argP1);
-        argP1 = arg;
-        IncrementArguments(newArgs,argP1,argP2);
-        reducible = 1;
+        HandlePredicate(
+          cmSystemTools::FileIsFullPath((argP1)->c_str()),
+          reducible, arg, newArgs, argP1, argP2);
         }
       // does a command exist
       if (*arg == "COMMAND" && argP1  != newArgs.end())
         {
-        if(makefile->CommandExists((argP1)->c_str()))
-          {
-          *arg = "1";
-          }
-        else 
-          {
-          *arg = "0";
-          }
-        newArgs.erase(argP1);
-        argP1 = arg;
-        IncrementArguments(newArgs,argP1,argP2);
-        reducible = 1;
+        HandlePredicate(
+          makefile->CommandExists((argP1)->c_str()),
+          reducible, arg, newArgs, argP1, argP2);
         }
       // does a policy exist
       if (*arg == "POLICY" && argP1 != newArgs.end())
         {
         cmPolicies::PolicyID pid;
-        if(makefile->GetPolicies()->GetPolicyID((argP1)->c_str(), pid))
-          {
-          *arg = "1";
-          }
-        else
-          {
-          *arg = "0";
-          }
-        newArgs.erase(argP1);
-        argP1 = arg;
-        IncrementArguments(newArgs,argP1,argP2);
-        reducible = 1;
+        HandlePredicate(
+          makefile->GetPolicies()->GetPolicyID((argP1)->c_str(), pid),
+          reducible, arg, newArgs, argP1, argP2);
         }
       // is a variable defined
       if (*arg == "DEFINED" && argP1  != newArgs.end())
@@ -389,32 +429,30 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
           {
           bdef = makefile->IsDefinitionSet((argP1)->c_str());
           }
-        if(bdef)
-          {
-          *arg = "1";
-          }
-        else 
-          {
-          *arg = "0";
-          }
-        newArgs.erase(argP1);
-        argP1 = arg;
-        IncrementArguments(newArgs,argP1,argP2);
-        reducible = 1;
+        HandlePredicate(bdef, reducible, arg, newArgs, argP1, argP2);
         }
       ++arg;
       }
     }
   while (reducible);
+  return true;
+  }
 
-
-  // now loop through the arguments and see if we can reduce any of them
-  // we do this multiple times. Once for each level of precedence
+  //=========================================================================
+  // level two handles most binary operations except for AND  OR
+  bool HandleLevel2(std::list<std::string> &newArgs,
+                    cmMakefile *makefile,
+                    char **errorString)
+  {
+  int reducible;
+  const char *def;
+  const char *def2;
   do
     {
     reducible = 0;
     std::list<std::string>::iterator arg = newArgs.begin();
-
+    std::list<std::string>::iterator argP1;
+    std::list<std::string>::iterator argP2;
     while (arg != newArgs.end())
       {
       argP1 = arg;
@@ -468,49 +506,26 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
         def2 = cmIfCommand::GetVariableOrString((argP2)->c_str(), makefile);
         double lhs;
         double rhs;
+        bool result;
         if(sscanf(def, "%lg", &lhs) != 1 ||
            sscanf(def2, "%lg", &rhs) != 1)
           {
-          *arg = "0";
+          result = false;
           }
         else if (*(argP1) == "LESS")
           {
-          if(lhs < rhs)
-            {
-            *arg = "1";
-            }
-          else
-            {
-            *arg = "0";
-            }
+          result = (lhs < rhs);
           }
         else if (*(argP1) == "GREATER")
           {
-          if(lhs > rhs)
-            {
-            *arg = "1";
-            }
-          else
-            {
-            *arg = "0";
-            }
+          result = (lhs > rhs);
           }          
         else
           {
-          if(lhs == rhs)
-            {
-            *arg = "1";
-            }
-          else
-            {
-            *arg = "0";
-            }
+          result = (lhs == rhs);
           }          
-        newArgs.erase(argP2);
-        newArgs.erase(argP1);
-        argP1 = arg;
-        IncrementArguments(newArgs,argP1,argP2);
-        reducible = 1;
+        HandleBinaryOp(result,
+          reducible, arg, newArgs, argP1, argP2);
         }
 
       if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
@@ -521,7 +536,7 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
         def = cmIfCommand::GetVariableOrString(arg->c_str(), makefile);
         def2 = cmIfCommand::GetVariableOrString((argP2)->c_str(), makefile);
         int val = strcmp(def,def2);
-        int result;
+        bool result;
         if (*(argP1) == "STRLESS")
           {
           result = (val < 0);
@@ -534,19 +549,8 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
           {
           result = (val == 0);
           }
-        if(result)
-          {
-          *arg = "1";
-          }
-        else
-          {
-          *arg = "0";
-          }
-        newArgs.erase(argP2);
-        newArgs.erase(argP1);
-        argP1 = arg;
-        IncrementArguments(newArgs,argP1,argP2);
-        reducible = 1;
+        HandleBinaryOp(result,
+          reducible, arg, newArgs, argP1, argP2);
         }
 
       // is file A newer than file B
@@ -557,33 +561,32 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
         bool success=cmSystemTools::FileTimeCompare(arg->c_str(),
             (argP2)->c_str(),
             &fileIsNewer);
-        if(success==false || fileIsNewer==1 || fileIsNewer==0)
-          {
-          *arg = "1";
-          }
-        else
-          {
-          *arg = "0";
-          }
-        newArgs.erase(argP2);
-        newArgs.erase(argP1);
-        argP1 = arg;
-        IncrementArguments(newArgs,argP1,argP2);
-        reducible = 1;
+        HandleBinaryOp(
+          (success==false || fileIsNewer==1 || fileIsNewer==0),
+          reducible, arg, newArgs, argP1, argP2);
         }
 
       ++arg;
       }
     }
   while (reducible);
+  return true;
+  }
 
-
-  // now loop through the arguments and see if we can reduce any of them
-  // we do this multiple times. Once for each level of precedence
+  //=========================================================================
+  // level 3 handles NOT
+  bool HandleLevel3(std::list<std::string> &newArgs,
+                    cmMakefile *makefile,
+                    char **)
+  {
+  int reducible;
+  const char *def;
   do
     {
     reducible = 0;
     std::list<std::string>::iterator arg = newArgs.begin();
+    std::list<std::string>::iterator argP1;
+    std::list<std::string>::iterator argP2;
     while (arg != newArgs.end())
       {
       argP1 = arg;
@@ -591,30 +594,31 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
       if (argP1 != newArgs.end() && *arg == "NOT")
         {
         def = cmIfCommand::GetVariableOrNumber((argP1)->c_str(), makefile);
-        if(!cmSystemTools::IsOff(def))
-          {
-          *arg = "0";
-          }
-        else
-          {
-          *arg = "1";
-          }
-        newArgs.erase(argP1);
-        argP1 = arg;
-        IncrementArguments(newArgs,argP1,argP2);
-        reducible = 1;
+        HandlePredicate(cmSystemTools::IsOff(def),
+          reducible, arg, newArgs, argP1, argP2);
         }
       ++arg;
       }
     }
   while (reducible);
+  return true;
+  }
 
-  // now loop through the arguments and see if we can reduce any of them
-  // we do this multiple times. Once for each level of precedence
+  //=========================================================================
+  // level 4 handles AND OR
+  bool HandleLevel4(std::list<std::string> &newArgs,
+                    cmMakefile *makefile,
+                    char **)
+  {
+  int reducible;
+  const char *def;
+  const char *def2;
   do
     {
     reducible = 0;
     std::list<std::string>::iterator arg = newArgs.begin();
+    std::list<std::string>::iterator argP1;
+    std::list<std::string>::iterator argP2;
     while (arg != newArgs.end())
       {
       argP1 = arg;
@@ -624,19 +628,9 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
         {
         def = cmIfCommand::GetVariableOrNumber(arg->c_str(), makefile);
         def2 = cmIfCommand::GetVariableOrNumber((argP2)->c_str(), makefile);
-        if(cmSystemTools::IsOff(def) || cmSystemTools::IsOff(def2))
-          {
-          *arg = "0";
-          }
-        else
-          {
-          *arg = "1";
-          }
-        newArgs.erase(argP2);
-        newArgs.erase(argP1);
-        argP1 = arg;
-        IncrementArguments(newArgs,argP1,argP2);
-        reducible = 1;
+        HandleBinaryOp(
+          !(cmSystemTools::IsOff(def) || cmSystemTools::IsOff(def2)),
+          reducible, arg, newArgs, argP1, argP2);
         }
 
       if (argP1 != newArgs.end() && *(argP1) == "OR" && 
@@ -644,25 +638,84 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
         {
         def = cmIfCommand::GetVariableOrNumber(arg->c_str(), makefile);
         def2 = cmIfCommand::GetVariableOrNumber((argP2)->c_str(), makefile);
-        if(cmSystemTools::IsOff(def) && cmSystemTools::IsOff(def2))
-          {
-          *arg = "0";
-          }
-        else
-          {
-          *arg = "1";
-          }
-        newArgs.erase(argP2);
-        newArgs.erase(argP1);
-        argP1 = arg;
-        IncrementArguments(newArgs,argP1,argP2);
-        reducible = 1;
+        HandleBinaryOp(
+          !(cmSystemTools::IsOff(def) && cmSystemTools::IsOff(def2)),
+          reducible, arg, newArgs, argP1, argP2);
         }
-
       ++arg;
       }
     }
   while (reducible);
+  return true;
+  }
+}
+
+
+//=========================================================================
+// order of operations,
+// 1.   ( )   -- parenthetical groups 
+// 2.  IS_DIRECTORY EXISTS COMMAND DEFINED etc predicates 
+// 3. MATCHES LESS GREATER EQUAL STRLESS STRGREATER STREQUAL etc binary ops 
+// 4. NOT
+// 5. AND OR
+//
+// There is an issue on whether the arguments should be values of references,
+// for example IF (FOO AND BAR) should that compare the strings FOO and BAR
+// or should it really do IF (${FOO} AND ${BAR}) Currently IS_DIRECTORY
+// EXISTS COMMAND and DEFINED all take values. EQUAL, LESS and GREATER can
+// take numeric values or variable names. STRLESS and STRGREATER take
+// variable names but if the variable name is not found it will use the name
+// directly. AND OR take variables or the values 0 or 1.
+
+
+bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
+                         char **errorString, cmMakefile *makefile)
+{
+  // check for the different signatures
+  const char *def;
+  const char* msg = "Unknown arguments specified";
+  *errorString = new char[strlen(msg) + 1];
+  strcpy(*errorString, msg);
+
+  // handle empty invocation
+  if (args.size() < 1)
+    {
+    delete [] *errorString;
+    *errorString = 0;
+    return false;
+    }
+
+  // store the reduced args in this vector
+  std::list<std::string> newArgs;
+
+  // copy to the list structure
+  for(unsigned int i = 0; i < args.size(); ++i)
+    {   
+    newArgs.push_back(args[i]);
+    }
+
+  // now loop through the arguments and see if we can reduce any of them
+  // we do this multiple times. Once for each level of precedence
+  if (!HandleLevel0(newArgs, makefile, errorString)) // parens
+    {
+    return false;
+    }
+  if (!HandleLevel1(newArgs, makefile, errorString)) //predicates
+    {
+    return false;
+    }
+  if (!HandleLevel2(newArgs, makefile, errorString)) // binary ops
+    {
+    return false;
+    }
+  if (!HandleLevel3(newArgs, makefile, errorString)) // NOT
+    {
+    return false;
+    }
+  if (!HandleLevel4(newArgs, makefile, errorString)) // AND OR
+    {
+    return false;
+    }
 
   // now at the end there should only be one argument left
   if (newArgs.size() == 1)
@@ -687,6 +740,7 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
   return true;
 }
 
+//=========================================================================
 const char* cmIfCommand::GetVariableOrString(const char* str,
                                              const cmMakefile* mf)
 {
@@ -698,6 +752,7 @@ const char* cmIfCommand::GetVariableOrString(const char* str,
   return def;
 }
 
+//=========================================================================
 const char* cmIfCommand::GetVariableOrNumber(const char* str,
                                              const cmMakefile* mf)
 {

+ 17 - 2
Source/cmListFileCache.cxx

@@ -242,11 +242,26 @@ bool cmListFileCacheParseFunction(cmListFileLexer* lexer,
 
   // Arguments.
   unsigned long lastLine = cmListFileLexer_GetCurrentLine(lexer);
+  unsigned long parenDepth = 0;
   while((token = cmListFileLexer_Scan(lexer)))
     {
-    if(token->type == cmListFileLexer_Token_ParenRight)
+    if(token->type == cmListFileLexer_Token_ParenLeft)
       {
-      return true;
+      parenDepth++;
+      cmListFileArgument a("(",
+                           false, filename, token->line);
+      function.Arguments.push_back(a);
+      }
+    else if(token->type == cmListFileLexer_Token_ParenRight)
+      {
+      if (parenDepth == 0)
+        {
+        return true;
+        }
+      parenDepth--;
+      cmListFileArgument a(")",
+                           false, filename, token->line);
+      function.Arguments.push_back(a);        
       }
     else if(token->type == cmListFileLexer_Token_Identifier ||
             token->type == cmListFileLexer_Token_ArgumentUnquoted)

+ 6 - 0
Tests/Complex/CMakeLists.txt

@@ -336,6 +336,12 @@ if (NOT ELSEIF_RESULT EQUAL 2)
   set (ELSEIF_RESULT 0)
 endif (NOT ELSEIF_RESULT EQUAL 2)
 
+# test handling of parenthetical groups in conditionals
+if (2 GREATER 1 AND (4 LESS 3 OR 5 LESS 6) AND NOT (7 GREATER 8))
+  set(CONDITIONAL_PARENTHESES 1)
+endif()
+
+
 #
 # Configure file 
 # (plug vars to #define so that they can be tested)

+ 6 - 0
Tests/Complex/Executable/complex.cxx

@@ -369,6 +369,12 @@ int main()
   cmFailed("ELSEIF did not work");
 #endif
 
+#ifdef CONDITIONAL_PARENTHESES
+  cmPassed("CONDITIONAL_PARENTHESES did work");
+#else
+  cmFailed("CONDITIONAL_PARENTHESES did not work");
+#endif
+
   if(file2() != 1)
     {
     cmFailed("Call to file2 function from library failed.");

+ 4 - 0
Tests/Complex/cmTestConfigure.h.in

@@ -81,3 +81,7 @@
 
 // test elseif
 #cmakedefine ELSEIF_RESULT
+
+// test parenthesis in conditionals
+#cmakedefine CONDITIONAL_PARENTHESES
+

+ 6 - 0
Tests/ComplexOneConfig/CMakeLists.txt

@@ -336,6 +336,12 @@ if (NOT ELSEIF_RESULT EQUAL 2)
   set (ELSEIF_RESULT 0)
 endif (NOT ELSEIF_RESULT EQUAL 2)
 
+# test handling of parenthetical groups in conditionals
+if (2 GREATER 1 AND (4 LESS 3 OR 5 LESS 6) AND NOT (7 GREATER 8))
+  set(CONDITIONAL_PARENTHESES 1)
+endif()
+
+
 #
 # Configure file 
 # (plug vars to #define so that they can be tested)

+ 6 - 0
Tests/ComplexOneConfig/Executable/complex.cxx

@@ -369,6 +369,12 @@ int main()
   cmFailed("ELSEIF did not work");
 #endif
 
+#ifdef CONDITIONAL_PARENTHESES
+  cmPassed("CONDITIONAL_PARENTHESES did work");
+#else
+  cmFailed("CONDITIONAL_PARENTHESES did not work");
+#endif
+
   if(file2() != 1)
     {
     cmFailed("Call to file2 function from library failed.");

+ 4 - 0
Tests/ComplexOneConfig/cmTestConfigure.h.in

@@ -81,3 +81,7 @@
 
 // test elseif
 #cmakedefine ELSEIF_RESULT
+
+// test parenthesis in conditionals
+#cmakedefine CONDITIONAL_PARENTHESES
+

+ 6 - 0
Tests/ComplexRelativePaths/CMakeLists.txt

@@ -336,6 +336,12 @@ if (NOT ELSEIF_RESULT EQUAL 2)
   set (ELSEIF_RESULT 0)
 endif (NOT ELSEIF_RESULT EQUAL 2)
 
+# test handling of parenthetical groups in conditionals
+if (2 GREATER 1 AND (4 LESS 3 OR 5 LESS 6) AND NOT (7 GREATER 8))
+  set(CONDITIONAL_PARENTHESES 1)
+endif()
+
+
 #
 # Configure file 
 # (plug vars to #define so that they can be tested)

+ 6 - 0
Tests/ComplexRelativePaths/Executable/complex.cxx

@@ -369,6 +369,12 @@ int main()
   cmFailed("ELSEIF did not work");
 #endif
 
+#ifdef CONDITIONAL_PARENTHESES
+  cmPassed("CONDITIONAL_PARENTHESES did work");
+#else
+  cmFailed("CONDITIONAL_PARENTHESES did not work");
+#endif
+
   if(file2() != 1)
     {
     cmFailed("Call to file2 function from library failed.");

+ 4 - 0
Tests/ComplexRelativePaths/cmTestConfigure.h.in

@@ -81,3 +81,7 @@
 
 // test elseif
 #cmakedefine ELSEIF_RESULT
+
+// test parenthesis in conditionals
+#cmakedefine CONDITIONAL_PARENTHESES
+