Added a separate field for the language: FormatStyle::Syntax (feel free to 
suggest better names fot the field and the enumeration).
  Read multiple configurations, and extract one that matches the language (or 
is for "Any" language).

Hi djasper, klimek,

http://llvm-reviews.chandlerc.com/D2242

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D2242?vs=5709&id=5799#toc

Files:
  include/clang/Format/Format.h
  lib/Format/Format.cpp
  unittests/Format/FormatTest.cpp
Index: include/clang/Format/Format.h
===================================================================
--- include/clang/Format/Format.h
+++ include/clang/Format/Format.h
@@ -30,6 +30,21 @@
 /// \brief The \c FormatStyle is used to configure the formatting to follow
 /// specific guidelines.
 struct FormatStyle {
+  /// \brief Supported languages.
+  enum Language {
+    /// C++
+    Language_Cpp,
+    /// JavaScript
+    Language_JavaScript,
+    /// When stored in a configuration file, means that configuration
+    /// may be used for all languages. When passed to the reformat() function,
+    /// enables automatic language detection by file name.
+    Language_Any
+  };
+
+  /// \brief Language, this format style is targeted at.
+  Language Syntax;
+
   /// \brief The column limit.
   ///
   /// A column limit of \c 0 means that there is no column limit. In this case,
Index: lib/Format/Format.cpp
===================================================================
--- lib/Format/Format.cpp
+++ lib/Format/Format.cpp
@@ -34,6 +34,16 @@
 namespace llvm {
 namespace yaml {
 template <>
+struct ScalarEnumerationTraits<clang::format::FormatStyle::Language> {
+  static void enumeration(IO &IO, clang::format::FormatStyle::Language &Value) {
+    IO.enumCase(Value, "Cpp", clang::format::FormatStyle::Language_Cpp);
+    IO.enumCase(Value, "JavaScript",
+                clang::format::FormatStyle::Language_JavaScript);
+    IO.enumCase(Value, "Any", clang::format::FormatStyle::Language_Any);
+  }
+};
+
+template <>
 struct ScalarEnumerationTraits<clang::format::FormatStyle::LanguageStandard> {
   static void enumeration(IO &IO,
                           clang::format::FormatStyle::LanguageStandard &Value) {
@@ -106,6 +116,7 @@
         }
     }
 
+    IO.mapOptional("Syntax", Style.Syntax);
     IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset);
     IO.mapOptional("ConstructorInitializerIndentWidth",
                    Style.ConstructorInitializerIndentWidth);
@@ -173,6 +184,22 @@
     IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth);
   }
 };
+
+// Allows to read vector<FormatStyle> using the 0th element as a default value.
+template <>
+struct DocumentListTraits<std::vector<clang::format::FormatStyle> > {
+  static size_t size(IO &io, std::vector<clang::format::FormatStyle> &Seq) {
+    return Seq.size() - 1;
+  }
+  static clang::format::FormatStyle &
+  element(IO &io, std::vector<clang::format::FormatStyle> &Seq, size_t Index) {
+    if (Index + 2 > Seq.size()) {
+      clang::format::FormatStyle Template = Seq[0];
+      Seq.resize(Index + 2, Template);
+    }
+    return Seq[Index + 1];
+  }
+};
 }
 }
 
@@ -188,6 +215,7 @@
 
 FormatStyle getLLVMStyle() {
   FormatStyle LLVMStyle;
+  LLVMStyle.Syntax = FormatStyle::Language_Cpp;
   LLVMStyle.AccessModifierOffset = -2;
   LLVMStyle.AlignEscapedNewlinesLeft = false;
   LLVMStyle.AlignTrailingComments = true;
@@ -236,6 +264,7 @@
 
 FormatStyle getGoogleStyle() {
   FormatStyle GoogleStyle;
+  GoogleStyle.Syntax = FormatStyle::Language_Cpp;
   GoogleStyle.AccessModifierOffset = -1;
   GoogleStyle.AlignEscapedNewlinesLeft = true;
   GoogleStyle.AlignTrailingComments = true;
@@ -339,9 +368,20 @@
 llvm::error_code parseConfiguration(StringRef Text, FormatStyle *Style) {
   if (Text.trim().empty())
     return llvm::make_error_code(llvm::errc::invalid_argument);
+  std::vector<FormatStyle> Styles;
+  Styles.push_back(*Style);
   llvm::yaml::Input Input(Text);
-  Input >> *Style;
-  return Input.error();
+  Input >> Styles;
+  for (unsigned i = 1; i < Styles.size(); ++i) {
+    if ((Styles[i].Syntax == Styles[0].Syntax) ||
+        (Styles[i].Syntax == FormatStyle::Language_Any)) {
+      // FIXME: Error out on multiple configurations for the same language.
+      *Style = Styles[i];
+      Style->Syntax = Styles[0].Syntax;
+      return Input.error();
+    }
+  }
+  return llvm::make_error_code(llvm::errc::invalid_argument);
 }
 
 std::string configurationAsText(const FormatStyle &Style) {
@@ -979,24 +1019,40 @@
 
 private:
   void tryMergePreviousTokens() {
-    tryMerge_TMacro() || tryMergeJavaScriptIdentityOperators();
+    if (tryMerge_TMacro())
+      return;
+
+    if (Style.Syntax == FormatStyle::Language_JavaScript) {
+      static tok::TokenKind JSIdentity[] = { tok::equalequal, tok::equal };
+      static tok::TokenKind JSNotIdentity[] = { tok::exclaimequal, tok::equal };
+      static tok::TokenKind JSShiftEqual[] = { tok::greater, tok::greater,
+                                               tok::greaterequal };
+      // FIXME: We probably need to change token type to mimic operator with the
+      // correct priority.
+      tryMergeTokens(JSIdentity) || tryMergeTokens(JSNotIdentity) ||
+          tryMergeTokens(JSShiftEqual);
+    }
   }
 
-  bool tryMergeJavaScriptIdentityOperators() {
-    if (Tokens.size() < 2)
-      return false;
-    FormatToken &First = *Tokens[Tokens.size() - 2];
-    if (!First.isOneOf(tok::exclaimequal, tok::equalequal))
+  bool tryMergeTokens(ArrayRef<tok::TokenKind> Kinds) {
+    if (Tokens.size() < Kinds.size())
       return false;
-    FormatToken &Second = *Tokens.back();
-    if (!Second.is(tok::equal))
-      return false;
-    if (Second.WhitespaceRange.getBegin() != Second.WhitespaceRange.getEnd())
+
+    SmallVectorImpl<FormatToken *>::const_iterator First =
+        Tokens.end() - Kinds.size();
+    if (!First[0]->is(Kinds[0]))
       return false;
-    First.TokenText =
-        StringRef(First.TokenText.data(), First.TokenText.size() + 1);
-    First.ColumnWidth += 1;
-    Tokens.pop_back();
+    unsigned AddLength = 0;
+    for (unsigned i = 1; i < Kinds.size(); ++i) {
+      if (!First[i]->is(Kinds[i]) || First[i]->WhitespaceRange.getBegin() !=
+                                         First[i]->WhitespaceRange.getEnd())
+        return false;
+      AddLength += First[i]->TokenText.size();
+    }
+    Tokens.resize(Tokens.size() - Kinds.size() + 1);
+    First[0]->TokenText = StringRef(First[0]->TokenText.data(),
+                                    First[0]->TokenText.size() + AddLength);
+    First[0]->ColumnWidth += AddLength;
     return true;
   }
 
@@ -1206,6 +1262,9 @@
                        << (Encoding == encoding::Encoding_UTF8 ? "UTF8"
                                                                : "unknown")
                        << "\n");
+    // Should be in sync with the Language enum.
+    static const char *Languages[] = { "C++", "JavaScript", "Any" };
+    DEBUG(llvm::dbgs() << "Language: " << Languages[Style.Syntax] << "\n");
   }
 
   tooling::Replacements format() {
@@ -1496,6 +1555,9 @@
     "  -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
 
 FormatStyle getStyle(StringRef StyleName, StringRef FileName) {
+  // FIXME: Add language detection by file name.
+
+  // FIXME: Configure fallback style from outside (add a command line option).
   // Fallback style in case the rest of this function can't determine a style.
   StringRef FallbackStyle = "LLVM";
   FormatStyle Style;
Index: unittests/Format/FormatTest.cpp
===================================================================
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -6913,6 +6913,61 @@
   CHECK_PARSE("Standard: C++11", Standard, FormatStyle::LS_Cpp11);
   CHECK_PARSE("Standard: Auto", Standard, FormatStyle::LS_Auto);
 
+  Style.Syntax = FormatStyle::Language_Cpp;
+  CHECK_PARSE("Syntax: Cpp\n"
+              "IndentWidth: 12", IndentWidth, 12u);
+  EXPECT_EQ(parseConfiguration("Syntax: JavaScript\n"
+                               "IndentWidth: 34",
+                               &Style),
+            llvm::errc::invalid_argument);
+  EXPECT_EQ(Style.IndentWidth, 12u);
+  CHECK_PARSE("Syntax: Any\n"
+              "IndentWidth: 56", IndentWidth, 56u);
+  EXPECT_EQ(Style.Syntax, FormatStyle::Language_Cpp);
+
+  Style.Syntax = FormatStyle::Language_JavaScript;
+  CHECK_PARSE("Syntax: JavaScript\n"
+              "IndentWidth: 12", IndentWidth, 12u);
+  EXPECT_EQ(parseConfiguration("Syntax: Cpp\n"
+                               "IndentWidth: 34",
+                               &Style),
+            llvm::errc::invalid_argument);
+  EXPECT_EQ(Style.IndentWidth, 12u);
+  CHECK_PARSE("Syntax: Any\n"
+              "IndentWidth: 56", IndentWidth, 56u);
+  EXPECT_EQ(Style.Syntax, FormatStyle::Language_JavaScript);
+
+  CHECK_PARSE("---\n"
+              "Syntax: JavaScript\n"
+              "IndentWidth: 12\n"
+              "---\n"
+              "Syntax: Cpp\n"
+              "IndentWidth: 34\n"
+              "...\n",
+              IndentWidth, 12u);
+
+  Style.Syntax = FormatStyle::Language_Cpp;
+  CHECK_PARSE("---\n"
+              "Syntax: JavaScript\n"
+              "IndentWidth: 12\n"
+              "---\n"
+              "Syntax: Cpp\n"
+              "IndentWidth: 34\n"
+              "...\n",
+              IndentWidth, 34u);
+  CHECK_PARSE("---\n"
+              "Syntax: JavaScript\n"
+              "IndentWidth: 56\n"
+              "---\n"
+              "Syntax: Any\n"
+              "IndentWidth: 78\n"
+              "...\n",
+              IndentWidth, 78u);
+
+  // FIXME: Error out on multiple configs for the same language.
+
+  EXPECT_EQ(Style.Syntax, FormatStyle::Language_Cpp);
+
   Style.UseTab = FormatStyle::UT_ForIndentation;
   CHECK_PARSE("UseTab: false", UseTab, FormatStyle::UT_Never);
   CHECK_PARSE("UseTab: true", UseTab, FormatStyle::UT_Always);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to