From 878657074a3d65262d4c010dc2261ea688f19e8c Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Thu, 10 Apr 2014 07:37:33 +0000 Subject: [PATCH] YAMLIO: Allow scalars to dictate quotation rules Introduce ScalarTraits::mustQuote which determines whether or not a StringRef needs quoting before it is acceptable to output. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@205955 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/YamlIO.rst | 4 +- include/llvm/Object/YAML.h | 1 + include/llvm/Support/YAMLTraits.h | 114 ++++++++++++++++++++++-- lib/MC/MCModuleYAML.cpp | 2 + lib/Support/YAMLTraits.cpp | 14 +-- test/Object/X86/objdump-cfg-invalid-opcode.yaml | 2 +- unittests/Support/YAMLIOTest.cpp | 38 ++++++++ 7 files changed, 155 insertions(+), 20 deletions(-) diff --git a/docs/YamlIO.rst b/docs/YamlIO.rst index b1917b6469e..dfb348da2f4 100644 --- a/docs/YamlIO.rst +++ b/docs/YamlIO.rst @@ -426,8 +426,10 @@ looks like: static StringRef input(StringRef scalar, T &value) { // do custom parsing here. Return the empty string on success, // or an error message on failure. - return StringRef(); + return StringRef(); } + // Determine if this scalar needs quotes. + static bool mustQuote(StringRef) { return true; } }; diff --git a/include/llvm/Object/YAML.h b/include/llvm/Object/YAML.h index 89fe5047a86..1792e8b6267 100644 --- a/include/llvm/Object/YAML.h +++ b/include/llvm/Object/YAML.h @@ -108,6 +108,7 @@ template <> struct ScalarTraits { static void output(const object::yaml::BinaryRef &, void *, llvm::raw_ostream &); static StringRef input(StringRef, void *, object::yaml::BinaryRef &); + static bool mustQuote(StringRef S) { return needsQuotes(S); } }; } diff --git a/include/llvm/Support/YAMLTraits.h b/include/llvm/Support/YAMLTraits.h index 44db30ac6e9..50ab886c986 100644 --- a/include/llvm/Support/YAMLTraits.h +++ b/include/llvm/Support/YAMLTraits.h @@ -20,6 +20,7 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Regex.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/raw_ostream.h" @@ -98,6 +99,7 @@ struct ScalarBitSetTraits { /// // return empty string on success, or error string /// return StringRef(); /// } +/// static bool mustQuote(StringRef) { return true; } /// }; template struct ScalarTraits { @@ -109,6 +111,9 @@ struct ScalarTraits { // Function to convert a string to a value. Returns the empty // StringRef on success or an error string if string is malformed: //static StringRef input(StringRef scalar, void *ctxt, T &value); + // + // Function to determine if the value should be quoted. + //static bool mustQuote(StringRef); }; @@ -198,17 +203,19 @@ struct has_ScalarTraits { typedef StringRef (*Signature_input)(StringRef, void*, T&); typedef void (*Signature_output)(const T&, void*, llvm::raw_ostream&); + typedef bool (*Signature_mustQuote)(StringRef); template - static char test(SameType*, - SameType*); + static char test(SameType *, + SameType *, + SameType *); template static double test(...); public: static bool const value = - (sizeof(test >(nullptr,nullptr)) == 1); + (sizeof(test>(nullptr, nullptr, nullptr)) == 1); }; @@ -316,7 +323,81 @@ public: static bool const value = (sizeof(test >(0)) == 1); }; +inline bool isNumber(StringRef S) { + static const char OctalChars[] = "01234567"; + if (S.startswith("0") && + S.drop_front().find_first_not_of(OctalChars) == StringRef::npos) + return true; + + if (S.startswith("0o") && + S.drop_front(2).find_first_not_of(OctalChars) == StringRef::npos) + return true; + + static const char HexChars[] = "0123456789abcdefABCDEF"; + if (S.startswith("0x") && + S.drop_front(2).find_first_not_of(HexChars) == StringRef::npos) + return true; + + static const char DecChars[] = "0123456789"; + if (S.find_first_not_of(DecChars) == StringRef::npos) + return true; + + if (S.equals(".inf") || S.equals(".Inf") || S.equals(".INF")) + return true; + + Regex FloatMatcher("^(\\.[0-9]+|[0-9]+(\\.[0-9]*)?)([eE][-+]?[0-9]+)?$"); + if (FloatMatcher.match(S)) + return true; + + return false; +} + +inline bool isNumeric(StringRef S) { + if ((S.front() == '-' || S.front() == '+') && isNumber(S.drop_front())) + return true; + if (isNumber(S)) + return true; + + if (S.equals(".nan") || S.equals(".NaN") || S.equals(".NAN")) + return true; + + return false; +} + +inline bool isNull(StringRef S) { + return S.equals("null") || S.equals("Null") || S.equals("NULL") || + S.equals("~"); +} + +inline bool isBool(StringRef S) { + return S.equals("true") || S.equals("True") || S.equals("TRUE") || + S.equals("false") || S.equals("False") || S.equals("FALSE"); +} + +inline bool needsQuotes(StringRef S) { + if (S.empty()) + return true; + if (isspace(S.front()) || isspace(S.back())) + return true; + if (S.front() == ',') + return true; + + static const char ScalarSafeChars[] = + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-/^., \t"; + if (S.find_first_not_of(ScalarSafeChars) != StringRef::npos) + return true; + + if (isNull(S)) + return true; + if (isBool(S)) + return true; + if (isNumeric(S)) + return true; + + return false; +} template @@ -371,7 +452,7 @@ public: virtual bool bitSetMatch(const char*, bool) = 0; virtual void endBitSetScalar() = 0; - virtual void scalarString(StringRef &) = 0; + virtual void scalarString(StringRef &, bool) = 0; virtual void setError(const Twine &) = 0; @@ -521,11 +602,11 @@ yamlize(IO &io, T &Val, bool) { llvm::raw_string_ostream Buffer(Storage); ScalarTraits::output(Val, io.getContext(), Buffer); StringRef Str = Buffer.str(); - io.scalarString(Str); + io.scalarString(Str, ScalarTraits::mustQuote(Str)); } else { StringRef Str; - io.scalarString(Str); + io.scalarString(Str, ScalarTraits::mustQuote(Str)); StringRef Result = ScalarTraits::input(Str, io.getContext(), Val); if ( !Result.empty() ) { io.setError(llvm::Twine(Result)); @@ -602,78 +683,91 @@ template<> struct ScalarTraits { static void output(const bool &, void*, llvm::raw_ostream &); static StringRef input(StringRef, void*, bool &); + static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { static void output(const StringRef &, void*, llvm::raw_ostream &); static StringRef input(StringRef, void*, StringRef &); + static bool mustQuote(StringRef S) { return needsQuotes(S); } }; template<> struct ScalarTraits { static void output(const std::string &, void*, llvm::raw_ostream &); static StringRef input(StringRef, void*, std::string &); + static bool mustQuote(StringRef S) { return needsQuotes(S); } }; template<> struct ScalarTraits { static void output(const uint8_t &, void*, llvm::raw_ostream &); static StringRef input(StringRef, void*, uint8_t &); + static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { static void output(const uint16_t &, void*, llvm::raw_ostream &); static StringRef input(StringRef, void*, uint16_t &); + static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { static void output(const uint32_t &, void*, llvm::raw_ostream &); static StringRef input(StringRef, void*, uint32_t &); + static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { static void output(const uint64_t &, void*, llvm::raw_ostream &); static StringRef input(StringRef, void*, uint64_t &); + static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { static void output(const int8_t &, void*, llvm::raw_ostream &); static StringRef input(StringRef, void*, int8_t &); + static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { static void output(const int16_t &, void*, llvm::raw_ostream &); static StringRef input(StringRef, void*, int16_t &); + static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { static void output(const int32_t &, void*, llvm::raw_ostream &); static StringRef input(StringRef, void*, int32_t &); + static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { static void output(const int64_t &, void*, llvm::raw_ostream &); static StringRef input(StringRef, void*, int64_t &); + static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { static void output(const float &, void*, llvm::raw_ostream &); static StringRef input(StringRef, void*, float &); + static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { static void output(const double &, void*, llvm::raw_ostream &); static StringRef input(StringRef, void*, double &); + static bool mustQuote(StringRef) { return false; } }; @@ -795,7 +889,7 @@ private: bool beginBitSetScalar(bool &) override; bool bitSetMatch(const char *, bool ) override; void endBitSetScalar() override; - void scalarString(StringRef &) override; + void scalarString(StringRef &, bool) override; void setError(const Twine &message) override; bool canElideEmptySequence() override; @@ -920,7 +1014,7 @@ public: bool beginBitSetScalar(bool &) override; bool bitSetMatch(const char *, bool ) override; void endBitSetScalar() override; - void scalarString(StringRef &) override; + void scalarString(StringRef &, bool) override; void setError(const Twine &message) override; bool canElideEmptySequence() override; public: @@ -991,24 +1085,28 @@ template<> struct ScalarTraits { static void output(const Hex8 &, void*, llvm::raw_ostream &); static StringRef input(StringRef, void*, Hex8 &); + static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { static void output(const Hex16 &, void*, llvm::raw_ostream &); static StringRef input(StringRef, void*, Hex16 &); + static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { static void output(const Hex32 &, void*, llvm::raw_ostream &); static StringRef input(StringRef, void*, Hex32 &); + static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { static void output(const Hex64 &, void*, llvm::raw_ostream &); static StringRef input(StringRef, void*, Hex64 &); + static bool mustQuote(StringRef) { return false; } }; diff --git a/lib/MC/MCModuleYAML.cpp b/lib/MC/MCModuleYAML.cpp index 102971b7320..432652b0db9 100644 --- a/lib/MC/MCModuleYAML.cpp +++ b/lib/MC/MCModuleYAML.cpp @@ -162,12 +162,14 @@ template <> struct ScalarTraits { static void output(const MCModuleYAML::Operand &, void *, llvm::raw_ostream &); static StringRef input(StringRef, void *, MCModuleYAML::Operand &); + static bool mustQuote(StringRef) { return false; } }; template <> struct ScalarTraits { static void output(const MCModuleYAML::OpcodeEnum &, void *, llvm::raw_ostream &); static StringRef input(StringRef, void *, MCModuleYAML::OpcodeEnum &); + static bool mustQuote(StringRef) { return false; } }; void ScalarEnumerationTraits::enumeration( diff --git a/lib/Support/YAMLTraits.cpp b/lib/Support/YAMLTraits.cpp index f46f140abd8..e5f94947ff8 100644 --- a/lib/Support/YAMLTraits.cpp +++ b/lib/Support/YAMLTraits.cpp @@ -285,7 +285,7 @@ void Input::endBitSetScalar() { } } -void Input::scalarString(StringRef &S) { +void Input::scalarString(StringRef &S, bool) { if (ScalarHNode *SN = dyn_cast(CurrentNode)) { S = SN->value(); } else { @@ -541,10 +541,7 @@ void Output::endBitSetScalar() { this->outputUpToEndOfLine(" ]"); } -void Output::scalarString(StringRef &S) { - const char ScalarSafeChars[] = "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-/^., \t"; - +void Output::scalarString(StringRef &S, bool MustQuote) { this->newLineCheck(); if (S.empty()) { // Print '' for the empty string because leaving the field empty is not @@ -552,11 +549,8 @@ void Output::scalarString(StringRef &S) { this->outputUpToEndOfLine("''"); return; } - bool isOctalString = S.front() == '0' && S.size() > 2 && !S.startswith("0x"); - if (S.find_first_not_of(ScalarSafeChars) == StringRef::npos && - !isspace(S.front()) && !isspace(S.back()) && !isOctalString) { - // If the string consists only of safe characters, print it out without - // quotes. + if (!MustQuote) { + // Only quote if we must. this->outputUpToEndOfLine(S); return; } diff --git a/test/Object/X86/objdump-cfg-invalid-opcode.yaml b/test/Object/X86/objdump-cfg-invalid-opcode.yaml index 56ab1d274ee..d0a29be8697 100644 --- a/test/Object/X86/objdump-cfg-invalid-opcode.yaml +++ b/test/Object/X86/objdump-cfg-invalid-opcode.yaml @@ -38,7 +38,7 @@ Sections: #CFG: Type: Data ## 4: 06 (bad) -#CFG: Content: 06 +#CFG: Content: '06' #CFG: - StartAddress: 0x0000000000000005 #CFG: Size: 1 diff --git a/unittests/Support/YAMLIOTest.cpp b/unittests/Support/YAMLIOTest.cpp index 0f1951f4fcb..cf95532141e 100644 --- a/unittests/Support/YAMLIOTest.cpp +++ b/unittests/Support/YAMLIOTest.cpp @@ -303,12 +303,22 @@ struct StringTypes { llvm::StringRef str4; llvm::StringRef str5; llvm::StringRef str6; + llvm::StringRef str7; + llvm::StringRef str8; + llvm::StringRef str9; + llvm::StringRef str10; + llvm::StringRef str11; std::string stdstr1; std::string stdstr2; std::string stdstr3; std::string stdstr4; std::string stdstr5; std::string stdstr6; + std::string stdstr7; + std::string stdstr8; + std::string stdstr9; + std::string stdstr10; + std::string stdstr11; }; namespace llvm { @@ -322,12 +332,22 @@ namespace yaml { io.mapRequired("str4", st.str4); io.mapRequired("str5", st.str5); io.mapRequired("str6", st.str6); + io.mapRequired("str7", st.str7); + io.mapRequired("str8", st.str8); + io.mapRequired("str9", st.str9); + io.mapRequired("str10", st.str10); + io.mapRequired("str11", st.str11); io.mapRequired("stdstr1", st.stdstr1); io.mapRequired("stdstr2", st.stdstr2); io.mapRequired("stdstr3", st.stdstr3); io.mapRequired("stdstr4", st.stdstr4); io.mapRequired("stdstr5", st.stdstr5); io.mapRequired("stdstr6", st.stdstr6); + io.mapRequired("stdstr7", st.stdstr7); + io.mapRequired("stdstr8", st.stdstr8); + io.mapRequired("stdstr9", st.stdstr9); + io.mapRequired("stdstr10", st.stdstr10); + io.mapRequired("stdstr11", st.stdstr11); } }; } @@ -343,12 +363,22 @@ TEST(YAMLIO, TestReadWriteStringTypes) { map.str4 = "@ddd"; map.str5 = ""; map.str6 = "0000000004000000"; + map.str7 = "true"; + map.str8 = "FALSE"; + map.str9 = "~"; + map.str10 = "0.2e20"; + map.str11 = "0x30"; map.stdstr1 = "'eee"; map.stdstr2 = "\"fff"; map.stdstr3 = "`ggg"; map.stdstr4 = "@hhh"; map.stdstr5 = ""; map.stdstr6 = "0000000004000000"; + map.stdstr7 = "true"; + map.stdstr8 = "FALSE"; + map.stdstr9 = "~"; + map.stdstr10 = "0.2e20"; + map.stdstr11 = "0x30"; llvm::raw_string_ostream ostr(intermediate); Output yout(ostr); @@ -362,6 +392,11 @@ TEST(YAMLIO, TestReadWriteStringTypes) { EXPECT_NE(llvm::StringRef::npos, flowOut.find("'@ddd'")); EXPECT_NE(llvm::StringRef::npos, flowOut.find("''\n")); EXPECT_NE(llvm::StringRef::npos, flowOut.find("'0000000004000000'\n")); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("'true'\n")); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("'FALSE'\n")); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("'~'\n")); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("'0.2e20'\n")); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("'0x30'\n")); EXPECT_NE(std::string::npos, flowOut.find("'''eee")); EXPECT_NE(std::string::npos, flowOut.find("'\"fff'")); EXPECT_NE(std::string::npos, flowOut.find("'`ggg'")); @@ -612,6 +647,7 @@ namespace yaml { return "malformed by"; } } + static bool mustQuote(StringRef) { return true; } }; } } @@ -673,6 +709,8 @@ namespace yaml { value = n; return StringRef(); } + + static bool mustQuote(StringRef) { return false; } }; } } -- 2.11.0