2012-12-13 04:46:15 +08:00
|
|
|
//===- lib/Support/YAMLTraits.cpp -----------------------------------------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2012-12-13 04:46:15 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2015-03-24 02:07:13 +08:00
|
|
|
#include "llvm/Support/YAMLTraits.h"
|
2017-06-22 07:19:47 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2015-03-24 02:07:13 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
2017-06-23 20:55:02 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2017-06-22 07:19:47 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2012-12-13 04:46:15 +08:00
|
|
|
#include "llvm/ADT/Twine.h"
|
|
|
|
#include "llvm/Support/Casting.h"
|
2015-03-24 02:07:13 +08:00
|
|
|
#include "llvm/Support/Errc.h"
|
2012-12-13 04:46:15 +08:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2012-12-13 04:55:44 +08:00
|
|
|
#include "llvm/Support/Format.h"
|
2015-05-15 07:08:22 +08:00
|
|
|
#include "llvm/Support/LineIterator.h"
|
2017-06-22 07:19:47 +08:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
2017-12-19 01:38:03 +08:00
|
|
|
#include "llvm/Support/Unicode.h"
|
2012-12-13 04:46:15 +08:00
|
|
|
#include "llvm/Support/YAMLParser.h"
|
2012-12-13 04:55:44 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2017-06-22 07:19:47 +08:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <cstdlib>
|
2014-01-07 19:48:04 +08:00
|
|
|
#include <cstring>
|
2017-06-22 07:19:47 +08:00
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
using namespace llvm;
|
|
|
|
using namespace yaml;
|
2012-12-13 04:46:15 +08:00
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// IO
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-06-22 07:19:47 +08:00
|
|
|
IO::IO(void *Context) : Ctxt(Context) {}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2017-06-22 07:19:47 +08:00
|
|
|
IO::~IO() = default;
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2019-08-30 21:39:22 +08:00
|
|
|
void *IO::getContext() const {
|
2012-12-13 04:46:15 +08:00
|
|
|
return Ctxt;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IO::setContext(void *Context) {
|
|
|
|
Ctxt = Context;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Input
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2016-11-29 05:38:52 +08:00
|
|
|
Input::Input(StringRef InputContent, void *Ctxt,
|
|
|
|
SourceMgr::DiagHandlerTy DiagHandler, void *DiagHandlerCtxt)
|
2017-06-22 07:19:47 +08:00
|
|
|
: IO(Ctxt), Strm(new Stream(InputContent, SrcMgr, false, &EC)) {
|
2013-11-18 23:50:04 +08:00
|
|
|
if (DiagHandler)
|
|
|
|
SrcMgr.setDiagHandler(DiagHandler, DiagHandlerCtxt);
|
2012-12-13 04:46:15 +08:00
|
|
|
DocIterator = Strm->begin();
|
|
|
|
}
|
|
|
|
|
2017-07-17 19:41:30 +08:00
|
|
|
Input::Input(MemoryBufferRef Input, void *Ctxt,
|
|
|
|
SourceMgr::DiagHandlerTy DiagHandler, void *DiagHandlerCtxt)
|
|
|
|
: IO(Ctxt), Strm(new Stream(Input, SrcMgr, false, &EC)) {
|
|
|
|
if (DiagHandler)
|
|
|
|
SrcMgr.setDiagHandler(DiagHandler, DiagHandlerCtxt);
|
|
|
|
DocIterator = Strm->begin();
|
|
|
|
}
|
|
|
|
|
2017-06-22 07:19:47 +08:00
|
|
|
Input::~Input() = default;
|
2013-01-09 05:04:44 +08:00
|
|
|
|
2014-06-13 10:24:39 +08:00
|
|
|
std::error_code Input::error() { return EC; }
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2013-11-19 08:57:56 +08:00
|
|
|
// Pin the vtables to this file.
|
|
|
|
void Input::HNode::anchor() {}
|
|
|
|
void Input::EmptyHNode::anchor() {}
|
|
|
|
void Input::ScalarHNode::anchor() {}
|
2014-09-16 02:39:24 +08:00
|
|
|
void Input::MapHNode::anchor() {}
|
|
|
|
void Input::SequenceHNode::anchor() {}
|
2013-11-19 08:57:56 +08:00
|
|
|
|
2019-08-30 21:39:22 +08:00
|
|
|
bool Input::outputting() const {
|
2012-12-13 04:46:15 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Input::setCurrentDocument() {
|
2012-12-13 06:40:02 +08:00
|
|
|
if (DocIterator != Strm->end()) {
|
2012-12-13 04:46:15 +08:00
|
|
|
Node *N = DocIterator->getRoot();
|
2013-11-18 23:50:04 +08:00
|
|
|
if (!N) {
|
2014-06-14 01:20:48 +08:00
|
|
|
EC = make_error_code(errc::invalid_argument);
|
2013-11-18 23:50:04 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
if (isa<NullNode>(N)) {
|
2012-12-13 04:46:15 +08:00
|
|
|
// Empty files are allowed and ignored
|
|
|
|
++DocIterator;
|
|
|
|
return setCurrentDocument();
|
|
|
|
}
|
2018-10-11 02:14:02 +08:00
|
|
|
TopNode = createHNodes(N);
|
2013-01-09 05:04:44 +08:00
|
|
|
CurrentNode = TopNode.get();
|
2012-12-13 04:46:15 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-05-31 12:51:07 +08:00
|
|
|
bool Input::nextDocument() {
|
|
|
|
return ++DocIterator != Strm->end();
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
2013-11-14 15:08:49 +08:00
|
|
|
|
2015-05-28 02:02:19 +08:00
|
|
|
const Node *Input::getCurrentNode() const {
|
|
|
|
return CurrentNode ? CurrentNode->_node : nullptr;
|
|
|
|
}
|
|
|
|
|
2013-11-14 08:59:59 +08:00
|
|
|
bool Input::mapTag(StringRef Tag, bool Default) {
|
2019-04-25 17:59:55 +08:00
|
|
|
// CurrentNode can be null if setCurrentDocument() was unable to
|
|
|
|
// parse the document because it was invalid or empty.
|
|
|
|
if (!CurrentNode)
|
|
|
|
return false;
|
|
|
|
|
2013-11-14 15:08:56 +08:00
|
|
|
std::string foundTag = CurrentNode->_node->getVerbatimTag();
|
2013-11-14 08:59:59 +08:00
|
|
|
if (foundTag.empty()) {
|
|
|
|
// If no tag found and 'Tag' is the default, say it was found.
|
|
|
|
return Default;
|
|
|
|
}
|
2015-05-13 01:44:32 +08:00
|
|
|
// Return true iff found tag matches supplied tag.
|
2013-11-14 08:59:59 +08:00
|
|
|
return Tag.equals(foundTag);
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
|
|
|
void Input::beginMapping() {
|
2016-11-28 12:57:04 +08:00
|
|
|
if (EC)
|
2012-12-13 04:46:15 +08:00
|
|
|
return;
|
2013-11-18 23:50:04 +08:00
|
|
|
// CurrentNode can be null if the document is empty.
|
|
|
|
MapHNode *MN = dyn_cast_or_null<MapHNode>(CurrentNode);
|
2012-12-13 06:40:02 +08:00
|
|
|
if (MN) {
|
2012-12-13 04:46:15 +08:00
|
|
|
MN->ValidKeys.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-04 11:51:36 +08:00
|
|
|
std::vector<StringRef> Input::keys() {
|
|
|
|
MapHNode *MN = dyn_cast<MapHNode>(CurrentNode);
|
|
|
|
std::vector<StringRef> Ret;
|
|
|
|
if (!MN) {
|
|
|
|
setError(CurrentNode, "not a mapping");
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
for (auto &P : MN->Mapping)
|
|
|
|
Ret.push_back(P.first());
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
bool Input::preflightKey(const char *Key, bool Required, bool, bool &UseDefault,
|
|
|
|
void *&SaveInfo) {
|
2012-12-13 04:46:15 +08:00
|
|
|
UseDefault = false;
|
2016-11-28 12:57:04 +08:00
|
|
|
if (EC)
|
2012-12-13 04:46:15 +08:00
|
|
|
return false;
|
2013-11-18 23:50:04 +08:00
|
|
|
|
|
|
|
// CurrentNode is null for empty documents, which is an error in case required
|
|
|
|
// nodes are present.
|
|
|
|
if (!CurrentNode) {
|
|
|
|
if (Required)
|
2014-06-14 01:20:48 +08:00
|
|
|
EC = make_error_code(errc::invalid_argument);
|
2013-11-18 23:50:04 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
MapHNode *MN = dyn_cast<MapHNode>(CurrentNode);
|
|
|
|
if (!MN) {
|
Allow empty mappings for optional YAML input
Summary:
This change fixes a bug where `obj2yaml` can in some cases produce YAML that
causes `yaml2obj` to error.
The ELF YAML document structure has a `Sections` mapping, which contains three
mappings, all of which are optional: `Local`, `Global`, and `Weak.` Any one of
these can be missing, but if all three are missing, then `yaml2obj` errors. This
change allows YAML input for cases like this one.
I have tested this with check-llvm and check-lld, and all tests passed.
This change is the result of test failures while working on D39582, which
introduces a `DynamicSymbols` mapping, which will be empty at times.
Reviewers: compnerd, jakehehrlich, silvas, kledzik, mehdi_amini, pcc
Reviewed By: compnerd
Subscribers: silvas, llvm-commits
Differential Revision: https://reviews.llvm.org/D39908
llvm-svn: 318428
2017-11-17 01:46:11 +08:00
|
|
|
if (Required || !isa<EmptyHNode>(CurrentNode))
|
|
|
|
setError(CurrentNode, "not a mapping");
|
2020-06-12 04:18:40 +08:00
|
|
|
else
|
|
|
|
UseDefault = true;
|
2012-12-13 04:46:15 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
MN->ValidKeys.push_back(Key);
|
2014-09-16 02:39:24 +08:00
|
|
|
HNode *Value = MN->Mapping[Key].get();
|
2012-12-13 06:40:02 +08:00
|
|
|
if (!Value) {
|
|
|
|
if (Required)
|
2012-12-13 04:46:15 +08:00
|
|
|
setError(CurrentNode, Twine("missing required key '") + Key + "'");
|
|
|
|
else
|
|
|
|
UseDefault = true;
|
2012-12-13 06:40:02 +08:00
|
|
|
return false;
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
|
|
|
SaveInfo = CurrentNode;
|
|
|
|
CurrentNode = Value;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Input::postflightKey(void *saveInfo) {
|
2012-12-13 06:40:02 +08:00
|
|
|
CurrentNode = reinterpret_cast<HNode *>(saveInfo);
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Input::endMapping() {
|
2016-11-28 12:57:04 +08:00
|
|
|
if (EC)
|
2012-12-13 04:46:15 +08:00
|
|
|
return;
|
2013-11-18 23:50:04 +08:00
|
|
|
// CurrentNode can be null if the document is empty.
|
|
|
|
MapHNode *MN = dyn_cast_or_null<MapHNode>(CurrentNode);
|
2012-12-13 06:40:02 +08:00
|
|
|
if (!MN)
|
2012-12-13 04:46:15 +08:00
|
|
|
return;
|
2014-04-10 14:02:49 +08:00
|
|
|
for (const auto &NN : MN->Mapping) {
|
2017-01-05 04:10:43 +08:00
|
|
|
if (!is_contained(MN->ValidKeys, NN.first())) {
|
2014-09-16 02:39:24 +08:00
|
|
|
setError(NN.second.get(), Twine("unknown key '") + NN.first() + "'");
|
2012-12-13 04:46:15 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-05 04:11:40 +08:00
|
|
|
void Input::beginFlowMapping() { beginMapping(); }
|
|
|
|
|
|
|
|
void Input::endFlowMapping() { endMapping(); }
|
|
|
|
|
2012-12-13 04:46:15 +08:00
|
|
|
unsigned Input::beginSequence() {
|
2015-03-03 01:26:43 +08:00
|
|
|
if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode))
|
2012-12-13 04:46:15 +08:00
|
|
|
return SQ->Entries.size();
|
2015-03-03 01:26:43 +08:00
|
|
|
if (isa<EmptyHNode>(CurrentNode))
|
|
|
|
return 0;
|
|
|
|
// Treat case where there's a scalar "null" value as an empty sequence.
|
|
|
|
if (ScalarHNode *SN = dyn_cast<ScalarHNode>(CurrentNode)) {
|
|
|
|
if (isNull(SN->value()))
|
|
|
|
return 0;
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
2015-03-03 01:26:43 +08:00
|
|
|
// Any other type of HNode is an error.
|
|
|
|
setError(CurrentNode, "not a sequence");
|
2012-12-13 04:46:15 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2012-12-13 06:40:02 +08:00
|
|
|
|
2012-12-13 04:46:15 +08:00
|
|
|
void Input::endSequence() {
|
|
|
|
}
|
2012-12-13 06:40:02 +08:00
|
|
|
|
2012-12-13 04:46:15 +08:00
|
|
|
bool Input::preflightElement(unsigned Index, void *&SaveInfo) {
|
2016-11-28 12:57:04 +08:00
|
|
|
if (EC)
|
2012-12-13 04:46:15 +08:00
|
|
|
return false;
|
2012-12-13 06:40:02 +08:00
|
|
|
if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) {
|
2012-12-13 04:46:15 +08:00
|
|
|
SaveInfo = CurrentNode;
|
2014-09-16 02:39:24 +08:00
|
|
|
CurrentNode = SQ->Entries[Index].get();
|
2012-12-13 04:46:15 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2012-12-13 06:40:02 +08:00
|
|
|
|
2012-12-13 04:46:15 +08:00
|
|
|
void Input::postflightElement(void *SaveInfo) {
|
2012-12-13 06:40:02 +08:00
|
|
|
CurrentNode = reinterpret_cast<HNode *>(SaveInfo);
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
|
|
|
|
2015-03-03 01:26:43 +08:00
|
|
|
unsigned Input::beginFlowSequence() { return beginSequence(); }
|
2012-12-13 06:40:02 +08:00
|
|
|
|
2012-12-13 04:46:15 +08:00
|
|
|
bool Input::preflightFlowElement(unsigned index, void *&SaveInfo) {
|
2016-11-28 12:57:04 +08:00
|
|
|
if (EC)
|
2012-12-13 04:46:15 +08:00
|
|
|
return false;
|
2012-12-13 06:40:02 +08:00
|
|
|
if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) {
|
2012-12-13 04:46:15 +08:00
|
|
|
SaveInfo = CurrentNode;
|
2014-09-16 02:39:24 +08:00
|
|
|
CurrentNode = SQ->Entries[index].get();
|
2012-12-13 04:46:15 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2012-12-13 06:40:02 +08:00
|
|
|
|
2012-12-13 04:46:15 +08:00
|
|
|
void Input::postflightFlowElement(void *SaveInfo) {
|
2012-12-13 06:40:02 +08:00
|
|
|
CurrentNode = reinterpret_cast<HNode *>(SaveInfo);
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
2012-12-13 06:40:02 +08:00
|
|
|
|
2012-12-13 04:46:15 +08:00
|
|
|
void Input::endFlowSequence() {
|
|
|
|
}
|
|
|
|
|
|
|
|
void Input::beginEnumScalar() {
|
|
|
|
ScalarMatchFound = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Input::matchEnumScalar(const char *Str, bool) {
|
2012-12-13 06:40:02 +08:00
|
|
|
if (ScalarMatchFound)
|
2012-12-13 04:46:15 +08:00
|
|
|
return false;
|
2012-12-13 06:40:02 +08:00
|
|
|
if (ScalarHNode *SN = dyn_cast<ScalarHNode>(CurrentNode)) {
|
|
|
|
if (SN->value().equals(Str)) {
|
2012-12-13 04:46:15 +08:00
|
|
|
ScalarMatchFound = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-01-24 05:57:50 +08:00
|
|
|
bool Input::matchEnumFallback() {
|
|
|
|
if (ScalarMatchFound)
|
|
|
|
return false;
|
|
|
|
ScalarMatchFound = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-12-13 04:46:15 +08:00
|
|
|
void Input::endEnumScalar() {
|
2012-12-13 06:40:02 +08:00
|
|
|
if (!ScalarMatchFound) {
|
2012-12-13 04:46:15 +08:00
|
|
|
setError(CurrentNode, "unknown enumerated scalar");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Input::beginBitSetScalar(bool &DoClear) {
|
|
|
|
BitValuesUsed.clear();
|
2012-12-13 06:40:02 +08:00
|
|
|
if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) {
|
2012-12-13 04:46:15 +08:00
|
|
|
BitValuesUsed.insert(BitValuesUsed.begin(), SQ->Entries.size(), false);
|
2012-12-13 06:40:02 +08:00
|
|
|
} else {
|
2012-12-13 04:46:15 +08:00
|
|
|
setError(CurrentNode, "expected sequence of bit values");
|
|
|
|
}
|
|
|
|
DoClear = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Input::bitSetMatch(const char *Str, bool) {
|
2016-11-28 12:57:04 +08:00
|
|
|
if (EC)
|
2012-12-13 04:46:15 +08:00
|
|
|
return false;
|
2012-12-13 06:40:02 +08:00
|
|
|
if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) {
|
2012-12-13 04:46:15 +08:00
|
|
|
unsigned Index = 0;
|
2014-09-16 02:39:24 +08:00
|
|
|
for (auto &N : SQ->Entries) {
|
|
|
|
if (ScalarHNode *SN = dyn_cast<ScalarHNode>(N.get())) {
|
2012-12-13 06:40:02 +08:00
|
|
|
if (SN->value().equals(Str)) {
|
2012-12-13 04:46:15 +08:00
|
|
|
BitValuesUsed[Index] = true;
|
|
|
|
return true;
|
|
|
|
}
|
2012-12-13 06:40:02 +08:00
|
|
|
} else {
|
2012-12-13 04:46:15 +08:00
|
|
|
setError(CurrentNode, "unexpected scalar in sequence of bit values");
|
|
|
|
}
|
|
|
|
++Index;
|
|
|
|
}
|
2012-12-13 06:40:02 +08:00
|
|
|
} else {
|
2012-12-13 04:46:15 +08:00
|
|
|
setError(CurrentNode, "expected sequence of bit values");
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Input::endBitSetScalar() {
|
2016-11-28 12:57:04 +08:00
|
|
|
if (EC)
|
2012-12-13 04:46:15 +08:00
|
|
|
return;
|
2012-12-13 06:40:02 +08:00
|
|
|
if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) {
|
2012-12-13 04:46:15 +08:00
|
|
|
assert(BitValuesUsed.size() == SQ->Entries.size());
|
2012-12-13 06:40:02 +08:00
|
|
|
for (unsigned i = 0; i < SQ->Entries.size(); ++i) {
|
|
|
|
if (!BitValuesUsed[i]) {
|
2014-09-16 02:39:24 +08:00
|
|
|
setError(SQ->Entries[i].get(), "unknown bit value");
|
2012-12-13 04:46:15 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-19 01:38:03 +08:00
|
|
|
void Input::scalarString(StringRef &S, QuotingType) {
|
2012-12-13 06:40:02 +08:00
|
|
|
if (ScalarHNode *SN = dyn_cast<ScalarHNode>(CurrentNode)) {
|
2012-12-13 04:46:15 +08:00
|
|
|
S = SN->value();
|
2012-12-13 06:40:02 +08:00
|
|
|
} else {
|
2012-12-13 04:46:15 +08:00
|
|
|
setError(CurrentNode, "unexpected scalar");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-19 01:38:03 +08:00
|
|
|
void Input::blockScalarString(StringRef &S) { scalarString(S, QuotingType::None); }
|
2015-05-15 07:08:22 +08:00
|
|
|
|
2018-11-15 03:39:59 +08:00
|
|
|
void Input::scalarTag(std::string &Tag) {
|
|
|
|
Tag = CurrentNode->_node->getVerbatimTag();
|
|
|
|
}
|
|
|
|
|
2012-12-13 04:46:15 +08:00
|
|
|
void Input::setError(HNode *hnode, const Twine &message) {
|
2013-11-18 23:50:04 +08:00
|
|
|
assert(hnode && "HNode must not be NULL");
|
2018-10-11 02:14:02 +08:00
|
|
|
setError(hnode->_node, message);
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
|
|
|
|
2018-11-15 03:39:59 +08:00
|
|
|
NodeKind Input::getNodeKind() {
|
|
|
|
if (isa<ScalarHNode>(CurrentNode))
|
|
|
|
return NodeKind::Scalar;
|
|
|
|
else if (isa<MapHNode>(CurrentNode))
|
|
|
|
return NodeKind::Map;
|
|
|
|
else if (isa<SequenceHNode>(CurrentNode))
|
|
|
|
return NodeKind::Sequence;
|
|
|
|
llvm_unreachable("Unsupported node kind");
|
|
|
|
}
|
|
|
|
|
2012-12-13 04:46:15 +08:00
|
|
|
void Input::setError(Node *node, const Twine &message) {
|
|
|
|
Strm->printError(node, message);
|
2014-06-14 01:20:48 +08:00
|
|
|
EC = make_error_code(errc::invalid_argument);
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
|
|
|
|
2014-09-16 02:39:24 +08:00
|
|
|
std::unique_ptr<Input::HNode> Input::createHNodes(Node *N) {
|
2012-12-13 06:40:02 +08:00
|
|
|
SmallString<128> StringStorage;
|
|
|
|
if (ScalarNode *SN = dyn_cast<ScalarNode>(N)) {
|
2012-12-13 04:46:15 +08:00
|
|
|
StringRef KeyStr = SN->getValue(StringStorage);
|
2012-12-13 06:40:02 +08:00
|
|
|
if (!StringStorage.empty()) {
|
2012-12-13 04:46:15 +08:00
|
|
|
// Copy string to permanent storage
|
2015-08-05 22:16:38 +08:00
|
|
|
KeyStr = StringStorage.str().copy(StringAllocator);
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
2019-08-15 23:54:37 +08:00
|
|
|
return std::make_unique<ScalarHNode>(N, KeyStr);
|
2015-05-15 07:08:22 +08:00
|
|
|
} else if (BlockScalarNode *BSN = dyn_cast<BlockScalarNode>(N)) {
|
2015-08-05 22:16:38 +08:00
|
|
|
StringRef ValueCopy = BSN->getValue().copy(StringAllocator);
|
2019-08-15 23:54:37 +08:00
|
|
|
return std::make_unique<ScalarHNode>(N, ValueCopy);
|
2012-12-13 06:40:02 +08:00
|
|
|
} else if (SequenceNode *SQ = dyn_cast<SequenceNode>(N)) {
|
2019-08-15 23:54:37 +08:00
|
|
|
auto SQHNode = std::make_unique<SequenceHNode>(N);
|
2014-04-10 14:02:49 +08:00
|
|
|
for (Node &SN : *SQ) {
|
2018-10-11 02:14:02 +08:00
|
|
|
auto Entry = createHNodes(&SN);
|
2016-11-28 12:57:04 +08:00
|
|
|
if (EC)
|
2012-12-13 04:46:15 +08:00
|
|
|
break;
|
2014-09-16 02:39:24 +08:00
|
|
|
SQHNode->Entries.push_back(std::move(Entry));
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
2020-02-10 23:06:45 +08:00
|
|
|
return std::move(SQHNode);
|
2012-12-13 06:40:02 +08:00
|
|
|
} else if (MappingNode *Map = dyn_cast<MappingNode>(N)) {
|
2019-08-15 23:54:37 +08:00
|
|
|
auto mapHNode = std::make_unique<MapHNode>(N);
|
2014-04-10 14:02:49 +08:00
|
|
|
for (KeyValueNode &KVN : *Map) {
|
2014-08-08 21:58:00 +08:00
|
|
|
Node *KeyNode = KVN.getKey();
|
YAML parser robustness improvements
Summary: This patch fixes a number of bugs found in the YAML parser
through fuzzing. In general, this makes the parser more robust against
malformed inputs.
The fixes are mostly improved null checking and returning errors in
more cases. In some cases, asserts were changed to regular errors,
this provides the same robustness but also protects release builds
from the triggering conditions. This also improves the fuzzability of
the YAML parser since asserts can act as a roadblock to further
fuzzing once they're hit.
Each fix has a corresponding test case:
- TestAnchorMapError - Added proper null pointer handling in
`Stream::printError` if N is null and `KeyValueNode::getValue` if
getKey returns null, `Input::createHNodes` `dyn_casts` changed to
`dyn_cast_or_null` so the null pointer checks are actually able to
fail
- TestFlowSequenceTokenErrors - Added case in
`Document::parseBlockNode` for FlowMappingEnd, FlowSequenceEnd, or
FlowEntry tokens outside of mappings or sequences
- TestDirectiveMappingNoValue - Changed assert to regular error
return in `Scanner::scanValue`
- TestUnescapeInfiniteLoop - Fixed infinite loop in
`ScalarNode::unescapeDoubleQuoted` by returning an error for
unrecognized escape codes
- TestScannerUnexpectedCharacter - Changed asserts to regular error
returns in `Scanner::consume`
- TestUnknownDirective - For both of the inputs the stream doesn't
fail and correctly returns TK_Error, but there is no valid root
node for the document. There's no reasonable way to make the
scanner fail for unknown directives without breaking the YAML spec
(see spec-07-01.test). I think the assert is unnecessary given
that an error is still generated for this case.
The `SimpleKeys.clear()` line fixes a bug found by AddressSanitizer
triggered by multiple test cases - when TokenQueue is cleared
SimpleKeys is still holding dangling pointers into it, so SimpleKeys
should be cleared as well.
Patch by Thomas Finch!
Reviewers: chandlerc, Bigcheese, hintonda
Reviewed By: Bigcheese, hintonda
Subscribers: hintonda, kristina, beanz, dexonsmith, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D61608
2019-11-06 13:51:04 +08:00
|
|
|
ScalarNode *Key = dyn_cast_or_null<ScalarNode>(KeyNode);
|
2017-09-21 16:25:59 +08:00
|
|
|
Node *Value = KVN.getValue();
|
|
|
|
if (!Key || !Value) {
|
|
|
|
if (!Key)
|
|
|
|
setError(KeyNode, "Map key must be a scalar");
|
|
|
|
if (!Value)
|
|
|
|
setError(KeyNode, "Map value must not be empty");
|
2014-08-08 21:58:00 +08:00
|
|
|
break;
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
StringStorage.clear();
|
2017-09-21 16:25:59 +08:00
|
|
|
StringRef KeyStr = Key->getValue(StringStorage);
|
2012-12-13 06:40:02 +08:00
|
|
|
if (!StringStorage.empty()) {
|
2012-12-13 04:46:15 +08:00
|
|
|
// Copy string to permanent storage
|
2015-08-05 22:16:38 +08:00
|
|
|
KeyStr = StringStorage.str().copy(StringAllocator);
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
2018-10-11 02:14:02 +08:00
|
|
|
auto ValueHNode = createHNodes(Value);
|
2016-11-28 12:57:04 +08:00
|
|
|
if (EC)
|
2012-12-13 04:46:15 +08:00
|
|
|
break;
|
2014-09-16 02:39:24 +08:00
|
|
|
mapHNode->Mapping[KeyStr] = std::move(ValueHNode);
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
2020-02-10 23:06:45 +08:00
|
|
|
return std::move(mapHNode);
|
2012-12-13 06:40:02 +08:00
|
|
|
} else if (isa<NullNode>(N)) {
|
2019-08-15 23:54:37 +08:00
|
|
|
return std::make_unique<EmptyHNode>(N);
|
2012-12-13 06:40:02 +08:00
|
|
|
} else {
|
2012-12-13 04:46:15 +08:00
|
|
|
setError(N, "unknown node kind");
|
2014-04-07 12:17:22 +08:00
|
|
|
return nullptr;
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Input::setError(const Twine &Message) {
|
2018-10-11 02:14:02 +08:00
|
|
|
setError(CurrentNode, Message);
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
|
|
|
|
2013-08-16 07:17:53 +08:00
|
|
|
bool Input::canElideEmptySequence() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-12-13 04:46:15 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Output
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2015-05-30 01:56:28 +08:00
|
|
|
Output::Output(raw_ostream &yout, void *context, int WrapColumn)
|
2017-06-22 07:19:47 +08:00
|
|
|
: IO(context), Out(yout), WrapColumn(WrapColumn) {}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2017-06-22 07:19:47 +08:00
|
|
|
Output::~Output() = default;
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2019-08-30 21:39:22 +08:00
|
|
|
bool Output::outputting() const {
|
2012-12-13 04:46:15 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Output::beginMapping() {
|
|
|
|
StateStack.push_back(inMapFirstKey);
|
2019-07-12 12:51:31 +08:00
|
|
|
PaddingBeforeContainer = Padding;
|
|
|
|
Padding = "\n";
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
|
|
|
|
2013-11-14 08:59:59 +08:00
|
|
|
bool Output::mapTag(StringRef Tag, bool Use) {
|
|
|
|
if (Use) {
|
2016-06-29 05:10:26 +08:00
|
|
|
// If this tag is being written inside a sequence we should write the start
|
|
|
|
// of the sequence before writing the tag, otherwise the tag won't be
|
|
|
|
// attached to the element in the sequence, but rather the sequence itself.
|
2018-11-15 03:39:59 +08:00
|
|
|
bool SequenceElement = false;
|
|
|
|
if (StateStack.size() > 1) {
|
|
|
|
auto &E = StateStack[StateStack.size() - 2];
|
|
|
|
SequenceElement = inSeqAnyElement(E) || inFlowSeqAnyElement(E);
|
|
|
|
}
|
2016-06-29 05:10:26 +08:00
|
|
|
if (SequenceElement && StateStack.back() == inMapFirstKey) {
|
2018-10-11 02:14:02 +08:00
|
|
|
newLineCheck();
|
2016-06-29 05:10:26 +08:00
|
|
|
} else {
|
2018-10-11 02:14:02 +08:00
|
|
|
output(" ");
|
2016-06-29 05:10:26 +08:00
|
|
|
}
|
2018-10-11 02:14:02 +08:00
|
|
|
output(Tag);
|
2016-06-29 05:10:26 +08:00
|
|
|
if (SequenceElement) {
|
|
|
|
// If we're writing the tag during the first element of a map, the tag
|
|
|
|
// takes the place of the first element in the sequence.
|
|
|
|
if (StateStack.back() == inMapFirstKey) {
|
|
|
|
StateStack.pop_back();
|
|
|
|
StateStack.push_back(inMapOtherKey);
|
|
|
|
}
|
|
|
|
// Tags inside maps in sequences should act as keys in the map from a
|
|
|
|
// formatting perspective, so we always want a newline in a sequence.
|
2019-07-12 12:51:31 +08:00
|
|
|
Padding = "\n";
|
2016-06-29 05:10:26 +08:00
|
|
|
}
|
2013-11-14 08:59:59 +08:00
|
|
|
}
|
|
|
|
return Use;
|
|
|
|
}
|
|
|
|
|
2012-12-13 04:46:15 +08:00
|
|
|
void Output::endMapping() {
|
2018-11-15 03:39:59 +08:00
|
|
|
// If we did not map anything, we should explicitly emit an empty map
|
2019-07-12 12:51:31 +08:00
|
|
|
if (StateStack.back() == inMapFirstKey) {
|
|
|
|
Padding = PaddingBeforeContainer;
|
|
|
|
newLineCheck();
|
2018-11-15 03:39:59 +08:00
|
|
|
output("{}");
|
2019-07-12 12:51:31 +08:00
|
|
|
Padding = "\n";
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
StateStack.pop_back();
|
|
|
|
}
|
|
|
|
|
2017-01-04 11:51:36 +08:00
|
|
|
std::vector<StringRef> Output::keys() {
|
|
|
|
report_fatal_error("invalid call");
|
|
|
|
}
|
|
|
|
|
2012-12-13 04:46:15 +08:00
|
|
|
bool Output::preflightKey(const char *Key, bool Required, bool SameAsDefault,
|
2012-12-13 06:40:02 +08:00
|
|
|
bool &UseDefault, void *&) {
|
2012-12-13 04:46:15 +08:00
|
|
|
UseDefault = false;
|
2017-03-16 01:47:39 +08:00
|
|
|
if (Required || !SameAsDefault || WriteDefaultValues) {
|
2015-05-05 04:11:40 +08:00
|
|
|
auto State = StateStack.back();
|
|
|
|
if (State == inFlowMapFirstKey || State == inFlowMapOtherKey) {
|
|
|
|
flowKey(Key);
|
|
|
|
} else {
|
2018-10-11 02:14:02 +08:00
|
|
|
newLineCheck();
|
|
|
|
paddedKey(Key);
|
2015-05-05 04:11:40 +08:00
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
void Output::postflightKey(void *) {
|
|
|
|
if (StateStack.back() == inMapFirstKey) {
|
2012-12-13 04:46:15 +08:00
|
|
|
StateStack.pop_back();
|
|
|
|
StateStack.push_back(inMapOtherKey);
|
2015-05-05 04:11:40 +08:00
|
|
|
} else if (StateStack.back() == inFlowMapFirstKey) {
|
|
|
|
StateStack.pop_back();
|
|
|
|
StateStack.push_back(inFlowMapOtherKey);
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-05 04:11:40 +08:00
|
|
|
void Output::beginFlowMapping() {
|
|
|
|
StateStack.push_back(inFlowMapFirstKey);
|
2018-10-11 02:14:02 +08:00
|
|
|
newLineCheck();
|
2015-05-05 04:11:40 +08:00
|
|
|
ColumnAtMapFlowStart = Column;
|
|
|
|
output("{ ");
|
|
|
|
}
|
|
|
|
|
|
|
|
void Output::endFlowMapping() {
|
|
|
|
StateStack.pop_back();
|
2018-10-11 02:14:02 +08:00
|
|
|
outputUpToEndOfLine(" }");
|
2015-05-05 04:11:40 +08:00
|
|
|
}
|
|
|
|
|
2012-12-13 04:46:15 +08:00
|
|
|
void Output::beginDocuments() {
|
2018-10-11 02:14:02 +08:00
|
|
|
outputUpToEndOfLine("---");
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Output::preflightDocument(unsigned index) {
|
2012-12-13 06:40:02 +08:00
|
|
|
if (index > 0)
|
2018-10-11 02:14:02 +08:00
|
|
|
outputUpToEndOfLine("\n---");
|
2012-12-13 04:46:15 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Output::postflightDocument() {
|
|
|
|
}
|
|
|
|
|
|
|
|
void Output::endDocuments() {
|
|
|
|
output("\n...\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned Output::beginSequence() {
|
2018-11-15 03:39:59 +08:00
|
|
|
StateStack.push_back(inSeqFirstElement);
|
2019-07-12 12:51:31 +08:00
|
|
|
PaddingBeforeContainer = Padding;
|
|
|
|
Padding = "\n";
|
2012-12-13 04:46:15 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2012-12-13 06:40:02 +08:00
|
|
|
|
2012-12-13 04:46:15 +08:00
|
|
|
void Output::endSequence() {
|
2018-11-15 03:39:59 +08:00
|
|
|
// If we did not emit anything, we should explicitly emit an empty sequence
|
2019-07-12 12:51:31 +08:00
|
|
|
if (StateStack.back() == inSeqFirstElement) {
|
|
|
|
Padding = PaddingBeforeContainer;
|
|
|
|
newLineCheck();
|
2018-11-15 03:39:59 +08:00
|
|
|
output("[]");
|
2019-07-12 12:51:31 +08:00
|
|
|
Padding = "\n";
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
StateStack.pop_back();
|
|
|
|
}
|
2012-12-13 06:40:02 +08:00
|
|
|
|
|
|
|
bool Output::preflightElement(unsigned, void *&) {
|
2012-12-13 04:46:15 +08:00
|
|
|
return true;
|
|
|
|
}
|
2012-12-13 06:40:02 +08:00
|
|
|
|
|
|
|
void Output::postflightElement(void *) {
|
2018-11-15 03:39:59 +08:00
|
|
|
if (StateStack.back() == inSeqFirstElement) {
|
|
|
|
StateStack.pop_back();
|
|
|
|
StateStack.push_back(inSeqOtherElement);
|
|
|
|
} else if (StateStack.back() == inFlowSeqFirstElement) {
|
|
|
|
StateStack.pop_back();
|
|
|
|
StateStack.push_back(inFlowSeqOtherElement);
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned Output::beginFlowSequence() {
|
2018-11-15 03:39:59 +08:00
|
|
|
StateStack.push_back(inFlowSeqFirstElement);
|
2018-10-11 02:14:02 +08:00
|
|
|
newLineCheck();
|
2012-12-13 04:46:15 +08:00
|
|
|
ColumnAtFlowStart = Column;
|
|
|
|
output("[ ");
|
|
|
|
NeedFlowSequenceComma = false;
|
|
|
|
return 0;
|
|
|
|
}
|
2012-12-13 06:40:02 +08:00
|
|
|
|
2012-12-13 04:46:15 +08:00
|
|
|
void Output::endFlowSequence() {
|
|
|
|
StateStack.pop_back();
|
2018-10-11 02:14:02 +08:00
|
|
|
outputUpToEndOfLine(" ]");
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
2012-12-13 06:40:02 +08:00
|
|
|
|
|
|
|
bool Output::preflightFlowElement(unsigned, void *&) {
|
|
|
|
if (NeedFlowSequenceComma)
|
2012-12-13 04:46:15 +08:00
|
|
|
output(", ");
|
2015-05-30 01:56:28 +08:00
|
|
|
if (WrapColumn && Column > WrapColumn) {
|
2012-12-13 04:46:15 +08:00
|
|
|
output("\n");
|
2012-12-13 06:40:02 +08:00
|
|
|
for (int i = 0; i < ColumnAtFlowStart; ++i)
|
2012-12-13 04:46:15 +08:00
|
|
|
output(" ");
|
|
|
|
Column = ColumnAtFlowStart;
|
|
|
|
output(" ");
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2012-12-13 06:40:02 +08:00
|
|
|
|
|
|
|
void Output::postflightFlowElement(void *) {
|
2012-12-13 04:46:15 +08:00
|
|
|
NeedFlowSequenceComma = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Output::beginEnumScalar() {
|
|
|
|
EnumerationMatchFound = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Output::matchEnumScalar(const char *Str, bool Match) {
|
2012-12-13 06:40:02 +08:00
|
|
|
if (Match && !EnumerationMatchFound) {
|
2018-10-11 02:14:02 +08:00
|
|
|
newLineCheck();
|
|
|
|
outputUpToEndOfLine(Str);
|
2012-12-13 04:46:15 +08:00
|
|
|
EnumerationMatchFound = true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-01-24 05:57:50 +08:00
|
|
|
bool Output::matchEnumFallback() {
|
|
|
|
if (EnumerationMatchFound)
|
|
|
|
return false;
|
|
|
|
EnumerationMatchFound = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-12-13 04:46:15 +08:00
|
|
|
void Output::endEnumScalar() {
|
2012-12-13 06:40:02 +08:00
|
|
|
if (!EnumerationMatchFound)
|
2012-12-13 04:46:15 +08:00
|
|
|
llvm_unreachable("bad runtime enum value");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Output::beginBitSetScalar(bool &DoClear) {
|
2018-10-11 02:14:02 +08:00
|
|
|
newLineCheck();
|
2012-12-13 04:46:15 +08:00
|
|
|
output("[ ");
|
|
|
|
NeedBitValueComma = false;
|
|
|
|
DoClear = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Output::bitSetMatch(const char *Str, bool Matches) {
|
2012-12-13 06:40:02 +08:00
|
|
|
if (Matches) {
|
|
|
|
if (NeedBitValueComma)
|
2012-12-13 04:46:15 +08:00
|
|
|
output(", ");
|
2018-10-11 02:14:02 +08:00
|
|
|
output(Str);
|
2012-12-13 04:46:15 +08:00
|
|
|
NeedBitValueComma = true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Output::endBitSetScalar() {
|
2018-10-11 02:14:02 +08:00
|
|
|
outputUpToEndOfLine(" ]");
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
|
|
|
|
2017-12-19 01:38:03 +08:00
|
|
|
void Output::scalarString(StringRef &S, QuotingType MustQuote) {
|
2018-10-11 02:14:02 +08:00
|
|
|
newLineCheck();
|
2013-09-11 12:00:08 +08:00
|
|
|
if (S.empty()) {
|
|
|
|
// Print '' for the empty string because leaving the field empty is not
|
|
|
|
// allowed.
|
2018-10-11 02:14:02 +08:00
|
|
|
outputUpToEndOfLine("''");
|
2013-09-11 12:00:08 +08:00
|
|
|
return;
|
|
|
|
}
|
2017-12-19 01:38:03 +08:00
|
|
|
if (MustQuote == QuotingType::None) {
|
2014-04-10 15:37:33 +08:00
|
|
|
// Only quote if we must.
|
2018-10-11 02:14:02 +08:00
|
|
|
outputUpToEndOfLine(S);
|
2012-12-13 04:46:15 +08:00
|
|
|
return;
|
|
|
|
}
|
2017-12-19 01:38:03 +08:00
|
|
|
|
|
|
|
const char *const Quote = MustQuote == QuotingType::Single ? "'" : "\"";
|
|
|
|
output(Quote); // Starting quote.
|
|
|
|
|
[YAML] Escape non-printable multibyte UTF8 in Output::scalarString.
The existing YAML Output::scalarString code path includes a partial and
incorrect implementation of YAML escaping logic. In particular, the logic put
in place in rL321283 escapes non-printable bytes only if they are not part of a
multibyte UTF8 sequence; implicitly this means that all multibyte UTF8
sequences -- printable and non -- are passed through verbatim.
The simplest solution to this is to direct the Output::scalarString method to
use the standalone yaml::escape function, and this _almost_ works, except that
the existing code in that function _over_ escapes: any multibyte UTF8 sequence
is escaped, even printable ones. While this is permitted for YAML, it is also
more aggressive (and hard to read for non-English locales) than necessary,
and the entire point of rL321283 was to back off such aggressive over-escaping.
So in this change, I have both redirected Output::scalarString to use
yaml::escape _and_ modified yaml::escape to optionally restrict its escaping to
non-printables. This preserves behaviour of any existing clients while giving
them a path to more moderate escaping should they desire.
Reviewers: JDevlieghere, thegameg, MatzeB, vladimir.plyashkun
Reviewed By: thegameg
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D44863
llvm-svn: 328661
2018-03-28 03:52:45 +08:00
|
|
|
// When using double-quoted strings (and only in that case), non-printable characters may be
|
|
|
|
// present, and will be escaped using a variety of unicode-scalar and special short-form
|
|
|
|
// escapes. This is handled in yaml::escape.
|
|
|
|
if (MustQuote == QuotingType::Double) {
|
2019-04-11 22:57:34 +08:00
|
|
|
output(yaml::escape(S, /* EscapePrintable= */ false));
|
2018-10-11 02:14:02 +08:00
|
|
|
outputUpToEndOfLine(Quote);
|
[YAML] Escape non-printable multibyte UTF8 in Output::scalarString.
The existing YAML Output::scalarString code path includes a partial and
incorrect implementation of YAML escaping logic. In particular, the logic put
in place in rL321283 escapes non-printable bytes only if they are not part of a
multibyte UTF8 sequence; implicitly this means that all multibyte UTF8
sequences -- printable and non -- are passed through verbatim.
The simplest solution to this is to direct the Output::scalarString method to
use the standalone yaml::escape function, and this _almost_ works, except that
the existing code in that function _over_ escapes: any multibyte UTF8 sequence
is escaped, even printable ones. While this is permitted for YAML, it is also
more aggressive (and hard to read for non-English locales) than necessary,
and the entire point of rL321283 was to back off such aggressive over-escaping.
So in this change, I have both redirected Output::scalarString to use
yaml::escape _and_ modified yaml::escape to optionally restrict its escaping to
non-printables. This preserves behaviour of any existing clients while giving
them a path to more moderate escaping should they desire.
Reviewers: JDevlieghere, thegameg, MatzeB, vladimir.plyashkun
Reviewed By: thegameg
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D44863
llvm-svn: 328661
2018-03-28 03:52:45 +08:00
|
|
|
return;
|
|
|
|
}
|
2017-12-19 01:38:03 +08:00
|
|
|
|
2019-04-11 22:57:34 +08:00
|
|
|
unsigned i = 0;
|
|
|
|
unsigned j = 0;
|
|
|
|
unsigned End = S.size();
|
|
|
|
const char *Base = S.data();
|
|
|
|
|
[YAML] Escape non-printable multibyte UTF8 in Output::scalarString.
The existing YAML Output::scalarString code path includes a partial and
incorrect implementation of YAML escaping logic. In particular, the logic put
in place in rL321283 escapes non-printable bytes only if they are not part of a
multibyte UTF8 sequence; implicitly this means that all multibyte UTF8
sequences -- printable and non -- are passed through verbatim.
The simplest solution to this is to direct the Output::scalarString method to
use the standalone yaml::escape function, and this _almost_ works, except that
the existing code in that function _over_ escapes: any multibyte UTF8 sequence
is escaped, even printable ones. While this is permitted for YAML, it is also
more aggressive (and hard to read for non-English locales) than necessary,
and the entire point of rL321283 was to back off such aggressive over-escaping.
So in this change, I have both redirected Output::scalarString to use
yaml::escape _and_ modified yaml::escape to optionally restrict its escaping to
non-printables. This preserves behaviour of any existing clients while giving
them a path to more moderate escaping should they desire.
Reviewers: JDevlieghere, thegameg, MatzeB, vladimir.plyashkun
Reviewed By: thegameg
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D44863
llvm-svn: 328661
2018-03-28 03:52:45 +08:00
|
|
|
// When using single-quoted strings, any single quote ' must be doubled to be escaped.
|
|
|
|
while (j < End) {
|
|
|
|
if (S[j] == '\'') { // Escape quotes.
|
|
|
|
output(StringRef(&Base[i], j - i)); // "flush".
|
|
|
|
output(StringLiteral("''")); // Print it as ''
|
2012-12-13 04:46:15 +08:00
|
|
|
i = j + 1;
|
|
|
|
}
|
|
|
|
++j;
|
|
|
|
}
|
|
|
|
output(StringRef(&Base[i], j - i));
|
2018-10-11 02:14:02 +08:00
|
|
|
outputUpToEndOfLine(Quote); // Ending quote.
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
|
|
|
|
2015-05-15 07:08:22 +08:00
|
|
|
void Output::blockScalarString(StringRef &S) {
|
|
|
|
if (!StateStack.empty())
|
|
|
|
newLineCheck();
|
|
|
|
output(" |");
|
|
|
|
outputNewLine();
|
|
|
|
|
|
|
|
unsigned Indent = StateStack.empty() ? 1 : StateStack.size();
|
|
|
|
|
|
|
|
auto Buffer = MemoryBuffer::getMemBuffer(S, "", false);
|
|
|
|
for (line_iterator Lines(*Buffer, false); !Lines.is_at_end(); ++Lines) {
|
|
|
|
for (unsigned I = 0; I < Indent; ++I) {
|
|
|
|
output(" ");
|
|
|
|
}
|
|
|
|
output(*Lines);
|
|
|
|
outputNewLine();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-15 03:39:59 +08:00
|
|
|
void Output::scalarTag(std::string &Tag) {
|
|
|
|
if (Tag.empty())
|
|
|
|
return;
|
|
|
|
newLineCheck();
|
|
|
|
output(Tag);
|
|
|
|
output(" ");
|
|
|
|
}
|
|
|
|
|
2012-12-13 04:46:15 +08:00
|
|
|
void Output::setError(const Twine &message) {
|
|
|
|
}
|
|
|
|
|
2013-08-16 07:17:53 +08:00
|
|
|
bool Output::canElideEmptySequence() {
|
|
|
|
// Normally, with an optional key/value where the value is an empty sequence,
|
|
|
|
// the whole key/value can be not written. But, that produces wrong yaml
|
|
|
|
// if the key/value is the only thing in the map and the map is used in
|
|
|
|
// a sequence. This detects if the this sequence is the first key/value
|
2020-02-21 20:55:43 +08:00
|
|
|
// in map that itself is embedded in a sequence.
|
2013-09-11 08:53:07 +08:00
|
|
|
if (StateStack.size() < 2)
|
2013-08-16 07:17:53 +08:00
|
|
|
return true;
|
2013-09-11 08:53:07 +08:00
|
|
|
if (StateStack.back() != inMapFirstKey)
|
2013-08-16 07:17:53 +08:00
|
|
|
return true;
|
2018-11-15 03:39:59 +08:00
|
|
|
return !inSeqAnyElement(StateStack[StateStack.size() - 2]);
|
2013-08-16 07:17:53 +08:00
|
|
|
}
|
|
|
|
|
2012-12-13 04:46:15 +08:00
|
|
|
void Output::output(StringRef s) {
|
|
|
|
Column += s.size();
|
|
|
|
Out << s;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Output::outputUpToEndOfLine(StringRef s) {
|
2018-10-11 02:14:02 +08:00
|
|
|
output(s);
|
2018-11-15 03:39:59 +08:00
|
|
|
if (StateStack.empty() || (!inFlowSeqAnyElement(StateStack.back()) &&
|
|
|
|
!inFlowMapAnyKey(StateStack.back())))
|
2019-07-12 12:51:31 +08:00
|
|
|
Padding = "\n";
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Output::outputNewLine() {
|
|
|
|
Out << "\n";
|
|
|
|
Column = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if seq at top, indent as if map, then add "- "
|
|
|
|
// if seq in middle, use "- " if firstKey, else use " "
|
|
|
|
//
|
|
|
|
|
|
|
|
void Output::newLineCheck() {
|
2019-07-12 12:51:31 +08:00
|
|
|
if (Padding != "\n") {
|
|
|
|
output(Padding);
|
|
|
|
Padding = {};
|
2012-12-13 04:46:15 +08:00
|
|
|
return;
|
2019-07-12 12:51:31 +08:00
|
|
|
}
|
2018-10-11 02:14:02 +08:00
|
|
|
outputNewLine();
|
2019-07-12 12:51:31 +08:00
|
|
|
Padding = {};
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2018-11-15 03:39:59 +08:00
|
|
|
if (StateStack.size() == 0)
|
|
|
|
return;
|
|
|
|
|
2012-12-13 04:46:15 +08:00
|
|
|
unsigned Indent = StateStack.size() - 1;
|
|
|
|
bool OutputDash = false;
|
|
|
|
|
2018-11-15 03:39:59 +08:00
|
|
|
if (StateStack.back() == inSeqFirstElement ||
|
|
|
|
StateStack.back() == inSeqOtherElement) {
|
2012-12-13 04:46:15 +08:00
|
|
|
OutputDash = true;
|
2018-11-15 03:39:59 +08:00
|
|
|
} else if ((StateStack.size() > 1) &&
|
|
|
|
((StateStack.back() == inMapFirstKey) ||
|
|
|
|
inFlowSeqAnyElement(StateStack.back()) ||
|
|
|
|
(StateStack.back() == inFlowMapFirstKey)) &&
|
|
|
|
inSeqAnyElement(StateStack[StateStack.size() - 2])) {
|
2012-12-13 04:46:15 +08:00
|
|
|
--Indent;
|
|
|
|
OutputDash = true;
|
|
|
|
}
|
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
for (unsigned i = 0; i < Indent; ++i) {
|
2012-12-13 04:46:15 +08:00
|
|
|
output(" ");
|
|
|
|
}
|
2012-12-13 06:40:02 +08:00
|
|
|
if (OutputDash) {
|
2012-12-13 04:46:15 +08:00
|
|
|
output("- ");
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Output::paddedKey(StringRef key) {
|
|
|
|
output(key);
|
|
|
|
output(":");
|
|
|
|
const char *spaces = " ";
|
2012-12-13 06:40:02 +08:00
|
|
|
if (key.size() < strlen(spaces))
|
2019-07-12 12:51:31 +08:00
|
|
|
Padding = &spaces[key.size()];
|
2012-12-13 04:46:15 +08:00
|
|
|
else
|
2019-07-12 12:51:31 +08:00
|
|
|
Padding = " ";
|
2012-12-13 04:46:15 +08:00
|
|
|
}
|
|
|
|
|
2015-05-05 04:11:40 +08:00
|
|
|
void Output::flowKey(StringRef Key) {
|
|
|
|
if (StateStack.back() == inFlowMapOtherKey)
|
|
|
|
output(", ");
|
2015-05-30 01:56:28 +08:00
|
|
|
if (WrapColumn && Column > WrapColumn) {
|
2015-05-05 04:11:40 +08:00
|
|
|
output("\n");
|
|
|
|
for (int I = 0; I < ColumnAtMapFlowStart; ++I)
|
|
|
|
output(" ");
|
|
|
|
Column = ColumnAtMapFlowStart;
|
|
|
|
output(" ");
|
|
|
|
}
|
|
|
|
output(Key);
|
|
|
|
output(": ");
|
|
|
|
}
|
|
|
|
|
2018-11-15 03:39:59 +08:00
|
|
|
NodeKind Output::getNodeKind() { report_fatal_error("invalid call"); }
|
|
|
|
|
|
|
|
bool Output::inSeqAnyElement(InState State) {
|
|
|
|
return State == inSeqFirstElement || State == inSeqOtherElement;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Output::inFlowSeqAnyElement(InState State) {
|
|
|
|
return State == inFlowSeqFirstElement || State == inFlowSeqOtherElement;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Output::inMapAnyKey(InState State) {
|
|
|
|
return State == inMapFirstKey || State == inMapOtherKey;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Output::inFlowMapAnyKey(InState State) {
|
|
|
|
return State == inFlowMapFirstKey || State == inFlowMapOtherKey;
|
|
|
|
}
|
|
|
|
|
2012-12-13 04:46:15 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// traits for built-in types
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
void ScalarTraits<bool>::output(const bool &Val, void *, raw_ostream &Out) {
|
|
|
|
Out << (Val ? "true" : "false");
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
StringRef ScalarTraits<bool>::input(StringRef Scalar, void *, bool &Val) {
|
|
|
|
if (Scalar.equals("true")) {
|
|
|
|
Val = true;
|
2012-12-13 04:46:15 +08:00
|
|
|
return StringRef();
|
2012-12-13 06:40:02 +08:00
|
|
|
} else if (Scalar.equals("false")) {
|
|
|
|
Val = false;
|
2012-12-13 04:46:15 +08:00
|
|
|
return StringRef();
|
|
|
|
}
|
2012-12-13 06:40:02 +08:00
|
|
|
return "invalid boolean";
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
void ScalarTraits<StringRef>::output(const StringRef &Val, void *,
|
|
|
|
raw_ostream &Out) {
|
|
|
|
Out << Val;
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
StringRef ScalarTraits<StringRef>::input(StringRef Scalar, void *,
|
|
|
|
StringRef &Val) {
|
|
|
|
Val = Scalar;
|
|
|
|
return StringRef();
|
|
|
|
}
|
2015-01-27 02:02:18 +08:00
|
|
|
|
2013-11-20 01:28:21 +08:00
|
|
|
void ScalarTraits<std::string>::output(const std::string &Val, void *,
|
2020-05-20 23:06:41 +08:00
|
|
|
raw_ostream &Out) {
|
2013-11-20 01:28:21 +08:00
|
|
|
Out << Val;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef ScalarTraits<std::string>::input(StringRef Scalar, void *,
|
2020-05-20 23:06:41 +08:00
|
|
|
std::string &Val) {
|
2013-11-20 01:28:21 +08:00
|
|
|
Val = Scalar.str();
|
|
|
|
return StringRef();
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
void ScalarTraits<uint8_t>::output(const uint8_t &Val, void *,
|
|
|
|
raw_ostream &Out) {
|
|
|
|
// use temp uin32_t because ostream thinks uint8_t is a character
|
|
|
|
uint32_t Num = Val;
|
|
|
|
Out << Num;
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
StringRef ScalarTraits<uint8_t>::input(StringRef Scalar, void *, uint8_t &Val) {
|
|
|
|
unsigned long long n;
|
|
|
|
if (getAsUnsignedInteger(Scalar, 0, n))
|
|
|
|
return "invalid number";
|
|
|
|
if (n > 0xFF)
|
|
|
|
return "out of range number";
|
|
|
|
Val = n;
|
|
|
|
return StringRef();
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
void ScalarTraits<uint16_t>::output(const uint16_t &Val, void *,
|
|
|
|
raw_ostream &Out) {
|
|
|
|
Out << Val;
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
StringRef ScalarTraits<uint16_t>::input(StringRef Scalar, void *,
|
|
|
|
uint16_t &Val) {
|
|
|
|
unsigned long long n;
|
|
|
|
if (getAsUnsignedInteger(Scalar, 0, n))
|
|
|
|
return "invalid number";
|
|
|
|
if (n > 0xFFFF)
|
|
|
|
return "out of range number";
|
|
|
|
Val = n;
|
|
|
|
return StringRef();
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
void ScalarTraits<uint32_t>::output(const uint32_t &Val, void *,
|
|
|
|
raw_ostream &Out) {
|
|
|
|
Out << Val;
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
StringRef ScalarTraits<uint32_t>::input(StringRef Scalar, void *,
|
|
|
|
uint32_t &Val) {
|
|
|
|
unsigned long long n;
|
|
|
|
if (getAsUnsignedInteger(Scalar, 0, n))
|
|
|
|
return "invalid number";
|
|
|
|
if (n > 0xFFFFFFFFUL)
|
|
|
|
return "out of range number";
|
|
|
|
Val = n;
|
|
|
|
return StringRef();
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
void ScalarTraits<uint64_t>::output(const uint64_t &Val, void *,
|
|
|
|
raw_ostream &Out) {
|
|
|
|
Out << Val;
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
StringRef ScalarTraits<uint64_t>::input(StringRef Scalar, void *,
|
|
|
|
uint64_t &Val) {
|
|
|
|
unsigned long long N;
|
|
|
|
if (getAsUnsignedInteger(Scalar, 0, N))
|
|
|
|
return "invalid number";
|
|
|
|
Val = N;
|
|
|
|
return StringRef();
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
void ScalarTraits<int8_t>::output(const int8_t &Val, void *, raw_ostream &Out) {
|
|
|
|
// use temp in32_t because ostream thinks int8_t is a character
|
|
|
|
int32_t Num = Val;
|
|
|
|
Out << Num;
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
StringRef ScalarTraits<int8_t>::input(StringRef Scalar, void *, int8_t &Val) {
|
|
|
|
long long N;
|
|
|
|
if (getAsSignedInteger(Scalar, 0, N))
|
|
|
|
return "invalid number";
|
|
|
|
if ((N > 127) || (N < -128))
|
|
|
|
return "out of range number";
|
|
|
|
Val = N;
|
|
|
|
return StringRef();
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
void ScalarTraits<int16_t>::output(const int16_t &Val, void *,
|
|
|
|
raw_ostream &Out) {
|
|
|
|
Out << Val;
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
StringRef ScalarTraits<int16_t>::input(StringRef Scalar, void *, int16_t &Val) {
|
|
|
|
long long N;
|
|
|
|
if (getAsSignedInteger(Scalar, 0, N))
|
|
|
|
return "invalid number";
|
|
|
|
if ((N > INT16_MAX) || (N < INT16_MIN))
|
|
|
|
return "out of range number";
|
|
|
|
Val = N;
|
|
|
|
return StringRef();
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
void ScalarTraits<int32_t>::output(const int32_t &Val, void *,
|
|
|
|
raw_ostream &Out) {
|
|
|
|
Out << Val;
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
StringRef ScalarTraits<int32_t>::input(StringRef Scalar, void *, int32_t &Val) {
|
|
|
|
long long N;
|
|
|
|
if (getAsSignedInteger(Scalar, 0, N))
|
|
|
|
return "invalid number";
|
|
|
|
if ((N > INT32_MAX) || (N < INT32_MIN))
|
|
|
|
return "out of range number";
|
|
|
|
Val = N;
|
|
|
|
return StringRef();
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
void ScalarTraits<int64_t>::output(const int64_t &Val, void *,
|
|
|
|
raw_ostream &Out) {
|
|
|
|
Out << Val;
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
StringRef ScalarTraits<int64_t>::input(StringRef Scalar, void *, int64_t &Val) {
|
|
|
|
long long N;
|
|
|
|
if (getAsSignedInteger(Scalar, 0, N))
|
|
|
|
return "invalid number";
|
|
|
|
Val = N;
|
|
|
|
return StringRef();
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
void ScalarTraits<double>::output(const double &Val, void *, raw_ostream &Out) {
|
|
|
|
Out << format("%g", Val);
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
StringRef ScalarTraits<double>::input(StringRef Scalar, void *, double &Val) {
|
2017-06-23 20:55:02 +08:00
|
|
|
if (to_float(Scalar, Val))
|
|
|
|
return StringRef();
|
|
|
|
return "invalid floating point number";
|
2012-12-13 06:40:02 +08:00
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
void ScalarTraits<float>::output(const float &Val, void *, raw_ostream &Out) {
|
|
|
|
Out << format("%g", Val);
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
StringRef ScalarTraits<float>::input(StringRef Scalar, void *, float &Val) {
|
2017-06-23 20:55:02 +08:00
|
|
|
if (to_float(Scalar, Val))
|
|
|
|
return StringRef();
|
|
|
|
return "invalid floating point number";
|
2012-12-13 06:40:02 +08:00
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
void ScalarTraits<Hex8>::output(const Hex8 &Val, void *, raw_ostream &Out) {
|
|
|
|
uint8_t Num = Val;
|
|
|
|
Out << format("0x%02X", Num);
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
StringRef ScalarTraits<Hex8>::input(StringRef Scalar, void *, Hex8 &Val) {
|
|
|
|
unsigned long long n;
|
|
|
|
if (getAsUnsignedInteger(Scalar, 0, n))
|
|
|
|
return "invalid hex8 number";
|
|
|
|
if (n > 0xFF)
|
|
|
|
return "out of range hex8 number";
|
|
|
|
Val = n;
|
|
|
|
return StringRef();
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
void ScalarTraits<Hex16>::output(const Hex16 &Val, void *, raw_ostream &Out) {
|
|
|
|
uint16_t Num = Val;
|
|
|
|
Out << format("0x%04X", Num);
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
StringRef ScalarTraits<Hex16>::input(StringRef Scalar, void *, Hex16 &Val) {
|
|
|
|
unsigned long long n;
|
|
|
|
if (getAsUnsignedInteger(Scalar, 0, n))
|
|
|
|
return "invalid hex16 number";
|
|
|
|
if (n > 0xFFFF)
|
|
|
|
return "out of range hex16 number";
|
|
|
|
Val = n;
|
|
|
|
return StringRef();
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
void ScalarTraits<Hex32>::output(const Hex32 &Val, void *, raw_ostream &Out) {
|
|
|
|
uint32_t Num = Val;
|
|
|
|
Out << format("0x%08X", Num);
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
StringRef ScalarTraits<Hex32>::input(StringRef Scalar, void *, Hex32 &Val) {
|
|
|
|
unsigned long long n;
|
|
|
|
if (getAsUnsignedInteger(Scalar, 0, n))
|
|
|
|
return "invalid hex32 number";
|
|
|
|
if (n > 0xFFFFFFFFUL)
|
|
|
|
return "out of range hex32 number";
|
|
|
|
Val = n;
|
|
|
|
return StringRef();
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
void ScalarTraits<Hex64>::output(const Hex64 &Val, void *, raw_ostream &Out) {
|
|
|
|
uint64_t Num = Val;
|
|
|
|
Out << format("0x%016llX", Num);
|
|
|
|
}
|
2012-12-13 04:46:15 +08:00
|
|
|
|
2012-12-13 06:40:02 +08:00
|
|
|
StringRef ScalarTraits<Hex64>::input(StringRef Scalar, void *, Hex64 &Val) {
|
|
|
|
unsigned long long Num;
|
|
|
|
if (getAsUnsignedInteger(Scalar, 0, Num))
|
|
|
|
return "invalid hex64 number";
|
|
|
|
Val = Num;
|
|
|
|
return StringRef();
|
|
|
|
}
|