mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-07-28 03:25:23 +00:00
YAML I/O add support for validate()
MappingTrait template specializations can now have a validate() method which performs semantic checking. For details, see <http://llvm.org/docs/YamlIO.html>. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@195286 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -647,6 +647,44 @@ mappings, as long as they are convertable.
|
|||||||
To check a tag, inside your mapping() method you can use io.mapTag() to specify
|
To check a tag, inside your mapping() method you can use io.mapTag() to specify
|
||||||
what the tag should be. This will also add that tag when writing yaml.
|
what the tag should be. This will also add that tag when writing yaml.
|
||||||
|
|
||||||
|
Validation
|
||||||
|
----------
|
||||||
|
|
||||||
|
Sometimes in a yaml map, each key/value pair is valid, but the combination is
|
||||||
|
not. This is similar to something having no syntax errors, but still having
|
||||||
|
semantic errors. To support semantic level checking, YAML I/O allows
|
||||||
|
an optional ``validate()`` method in a MappingTraits template specialization.
|
||||||
|
|
||||||
|
When parsing yaml, the ``validate()`` method is call *after* all key/values in
|
||||||
|
the map have been processed. Any error message returned by the ``validate()``
|
||||||
|
method during input will be printed just a like a syntax error would be printed.
|
||||||
|
When writing yaml, the ``validate()`` method is called *before* the yaml
|
||||||
|
key/values are written. Any error during output will trigger an ``assert()``
|
||||||
|
because it is a programming error to have invalid struct values.
|
||||||
|
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
using llvm::yaml::MappingTraits;
|
||||||
|
using llvm::yaml::IO;
|
||||||
|
|
||||||
|
struct Stuff {
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct MappingTraits<Stuff> {
|
||||||
|
static void mapping(IO &io, Stuff &stuff) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
static StringRef validate(IO &io, Stuff &stuff) {
|
||||||
|
// Look at all fields in 'stuff' and if there
|
||||||
|
// are any bad values return a string describing
|
||||||
|
// the error. Otherwise return an empty string.
|
||||||
|
return StringRef();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
Sequence
|
Sequence
|
||||||
========
|
========
|
||||||
|
@@ -44,6 +44,8 @@ template<class T>
|
|||||||
struct MappingTraits {
|
struct MappingTraits {
|
||||||
// Must provide:
|
// Must provide:
|
||||||
// static void mapping(IO &io, T &fields);
|
// static void mapping(IO &io, T &fields);
|
||||||
|
// Optionally may provide:
|
||||||
|
// static StringRef validate(IO &io, T &fields);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -226,6 +228,23 @@ public:
|
|||||||
static bool const value = (sizeof(test<MappingTraits<T> >(0)) == 1);
|
static bool const value = (sizeof(test<MappingTraits<T> >(0)) == 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Test if MappingTraits<T>::validate() is defined on type T.
|
||||||
|
template <class T>
|
||||||
|
struct has_MappingValidateTraits
|
||||||
|
{
|
||||||
|
typedef StringRef (*Signature_validate)(class IO&, T&);
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
static char test(SameType<Signature_validate, &U::validate>*);
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
static double test(...);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static bool const value = (sizeof(test<MappingTraits<T> >(0)) == 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Test if SequenceTraits<T> is defined on type T.
|
// Test if SequenceTraits<T> is defined on type T.
|
||||||
template <class T>
|
template <class T>
|
||||||
@@ -309,7 +328,15 @@ struct missingTraits : public llvm::integral_constant<bool,
|
|||||||
&& !has_SequenceTraits<T>::value
|
&& !has_SequenceTraits<T>::value
|
||||||
&& !has_DocumentListTraits<T>::value > {};
|
&& !has_DocumentListTraits<T>::value > {};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct validatedMappingTraits : public llvm::integral_constant<bool,
|
||||||
|
has_MappingTraits<T>::value
|
||||||
|
&& has_MappingValidateTraits<T>::value> {};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct unvalidatedMappingTraits : public llvm::integral_constant<bool,
|
||||||
|
has_MappingTraits<T>::value
|
||||||
|
&& !has_MappingValidateTraits<T>::value> {};
|
||||||
// Base class for Input and Output.
|
// Base class for Input and Output.
|
||||||
class IO {
|
class IO {
|
||||||
public:
|
public:
|
||||||
@@ -483,7 +510,27 @@ yamlize(IO &io, T &Val, bool) {
|
|||||||
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
typename llvm::enable_if_c<has_MappingTraits<T>::value, void>::type
|
typename llvm::enable_if_c<validatedMappingTraits<T>::value, void>::type
|
||||||
|
yamlize(IO &io, T &Val, bool) {
|
||||||
|
io.beginMapping();
|
||||||
|
if (io.outputting()) {
|
||||||
|
StringRef Err = MappingTraits<T>::validate(io, Val);
|
||||||
|
if (!Err.empty()) {
|
||||||
|
llvm::errs() << Err << "\n";
|
||||||
|
assert(Err.empty() && "invalid struct trying to be written as yaml");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MappingTraits<T>::mapping(io, Val);
|
||||||
|
if (!io.outputting()) {
|
||||||
|
StringRef Err = MappingTraits<T>::validate(io, Val);
|
||||||
|
if (!Err.empty())
|
||||||
|
io.setError(Err);
|
||||||
|
}
|
||||||
|
io.endMapping();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
typename llvm::enable_if_c<unvalidatedMappingTraits<T>::value, void>::type
|
||||||
yamlize(IO &io, T &Val, bool) {
|
yamlize(IO &io, T &Val, bool) {
|
||||||
io.beginMapping();
|
io.beginMapping();
|
||||||
MappingTraits<T>::mapping(io, Val);
|
MappingTraits<T>::mapping(io, Val);
|
||||||
|
@@ -27,6 +27,13 @@ using llvm::yaml::Hex32;
|
|||||||
using llvm::yaml::Hex64;
|
using llvm::yaml::Hex64;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void suppressErrorMessages(const llvm::SMDiagnostic &, void *) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Test MappingTraits
|
// Test MappingTraits
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
@@ -1115,17 +1122,50 @@ TEST(YAMLIO, TestTaggedDocumentsWriteAndRead) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Test mapping validation
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
struct MyValidation {
|
||||||
|
double value;
|
||||||
|
};
|
||||||
|
|
||||||
|
LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(MyValidation)
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
namespace yaml {
|
||||||
|
template <>
|
||||||
|
struct MappingTraits<MyValidation> {
|
||||||
|
static void mapping(IO &io, MyValidation &d) {
|
||||||
|
io.mapRequired("value", d.value);
|
||||||
|
}
|
||||||
|
static StringRef validate(IO &io, MyValidation &d) {
|
||||||
|
if (d.value < 0)
|
||||||
|
return "negative value";
|
||||||
|
return StringRef();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Test that validate() is called and complains about the negative value.
|
||||||
|
//
|
||||||
|
TEST(YAMLIO, TestValidatingInput) {
|
||||||
|
std::vector<MyValidation> docList;
|
||||||
|
Input yin("--- \nvalue: 3.0\n"
|
||||||
|
"--- \nvalue: -1.0\n...\n",
|
||||||
|
NULL, suppressErrorMessages);
|
||||||
|
yin >> docList;
|
||||||
|
EXPECT_TRUE(yin.error());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Test error handling
|
// Test error handling
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void suppressErrorMessages(const llvm::SMDiagnostic &, void *) {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Test error handling of unknown enumerated scalar
|
// Test error handling of unknown enumerated scalar
|
||||||
//
|
//
|
||||||
|
Reference in New Issue
Block a user